diff --git a/.gitignore b/.gitignore index 914e43bf52d4a975464da295a54cab9d51b3f971..507af4884359d1bb8867e58d1646c045ebb7fc7c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ fr3_impedance_controller_real/build/ fr3_impedance_controller_sim/build/ fr3_ros1_mujoco_interface/build/ fr3_ps3_joy_publisher/build/ +test/build/ assets/data/matlab/*.asv assets/data/*.csv - # assets/data/*.bag diff --git a/assets/data/250208_contact_01.bag b/assets/data/250208_contact_01.bag new file mode 100644 index 0000000000000000000000000000000000000000..e78e36e90181dbabe15c50339041d1a85ef13072 Binary files /dev/null and b/assets/data/250208_contact_01.bag differ diff --git a/assets/data/250208_contact_02.bag b/assets/data/250208_contact_02.bag new file mode 100644 index 0000000000000000000000000000000000000000..4731655b23bfd46646160e7c2df04ae7a37c40ff Binary files /dev/null and b/assets/data/250208_contact_02.bag differ diff --git a/assets/data/bag2csv.md b/assets/data/bag2csv.md new file mode 100644 index 0000000000000000000000000000000000000000..66c039489585f28272d23ffbb8733397f2e013dc --- /dev/null +++ b/assets/data/bag2csv.md @@ -0,0 +1,5 @@ +``` +$ rosbag info <bag-file-name> +$ rostopic echo -b <bag-file-name> -p <topic-name> > output.txt +$ mv output.txt output.csv +``` \ No newline at end of file diff --git a/assets/data/matlab/experiment_data_analysis.m b/assets/data/matlab/experiment_data_analysis.m new file mode 100644 index 0000000000000000000000000000000000000000..b8354f365c9d78c2b4f1ee76e0d7c6dbbd8f5f69 --- /dev/null +++ b/assets/data/matlab/experiment_data_analysis.m @@ -0,0 +1,248 @@ +%% load data +clc; close all; clear; + +ctrl_state_file = '../rosbag/250208_contact_02_controller_state.csv'; +ctrl_state_data_table = readtable(ctrl_state_file); +ctrl_state_data_array = table2array(ctrl_state_data_table); +ctrl_state_data_array(:,2:4) = []; + +ft_sensor_file = '../rosbag/250208_contact_02_ft_sensor.csv'; +ft_sensor_data_table = readtable(ft_sensor_file); +ft_sensor_data_array = table2array(ft_sensor_data_table); +ft_sensor_data_array(:, 2:22) = []; + +%% +vec_size = [1, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 7, 7, 6, 6, 6, 6, 6]; +start_idx = [1, ]; + +for i = 1:length(vec_size) - 1 + start_idx(i+1) = start_idx(i) + vec_size(i); +end + +data_cell = cell(1, length(vec_size)); + +for i = 1:length(vec_size) + data_cell{i} = ctrl_state_data_array(:, start_idx(i):start_idx(i) + vec_size(i) - 1); +end + +t_ctrl = data_cell{1}; +ddq_eul= data_cell{2}; +ddq_mob = data_cell{3}; +ddq_sosml = data_cell{4}; +tau_d_dob = data_cell{5}; +tau_d_mob = data_cell{6}; +tau_d_sosml = data_cell{7}; +F_d_fr3 = data_cell{8}; +F_d_dob = data_cell{9}; +F_d_mob = data_cell{10}; +F_d_sosml = data_cell{11}; +ee_pose_des = data_cell{12}; +ee_pose_mes = data_cell{13}; +ee_vel_des = data_cell{14}; +ee_vel_mes = data_cell{15}; +ee_acc_eul = data_cell{16}; +ee_acc_mob = data_cell{17}; +ee_acc_sosml = data_cell{18}; + +%% + + +offset = ft_sensor_data_array(1, :); +t_ft = ft_sensor_data_array(:, 1); +Fx_ft = ft_sensor_data_array(:, 2) - offset(2); +Fy_ft = ft_sensor_data_array(:, 3) - offset(3); +Fz_ft = ft_sensor_data_array(:, 4) - offset(4); +Tx_ft = ft_sensor_data_array(:, 5) - offset(5); +Ty_ft = ft_sensor_data_array(:, 6) - offset(6); +Tz_ft = ft_sensor_data_array(:, 7) - offset(7); +%% + +t_start = t_ctrl(1); +t_end = t_ctrl(end); + +lw = 1.2; +font = 'Times New Roman'; +fs_lgd = 14; +fs_lbl = 22; +fs_axis = 14; +fs_title = 20; + +%% Joint acceleration +% close all; +figure(); +fig_ddq = tiledlayout(7, 1, "Padding", "compact", "TileSpacing", "compact"); +ytitles = {'$\ddot{q}_1$', '$\ddot{q}_2$', '$\ddot{q}_3$', '$\ddot{q}_4$', '$\ddot{q}_5$', ... + '$\ddot{q}_6$', '$\ddot{q}_7$',}; +plt_indices = 1:7; + +for i = 1:length(plt_indices) + nexttile; + hold on; + grid; + plot(t_ctrl, ddq_eul(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', 1.5 * lw, 'Color', 'k'); + plot(t_ctrl, ddq_mob(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', 1.5 * lw, 'Color', 'r'); + % plot(t, ddq_sosml(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', 2 * lw, 'Color', 'g'); + % plt2.Color(4) = 0.7; + xlim([t_start, t_end]); + % ylim([-5 5]); + + ylabel(ytitles(plt_indices(i)), 'Interpreter', 'latex', 'FontSize', fs_lbl) + + % if i == 7 + % ylim([-1 1]); + % end + + if i == 1 + legend('Euler method', 'MOB', 'SOSML', 'FontName', font, 'FontSize', fs_lgd, 'interpreter', 'latex'); + end +end + +title(fig_ddq, 'Joint Acceleration $[rad/s^2]$', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel(fig_ddq, 'Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); + +%% Task acceleration +% close all; +figure(); +fig_ddx = tiledlayout(6, 1, "Padding", "compact", "TileSpacing", "compact"); +ytitles = {'$\ddot{p}_x$', '$\ddot{p}_y$', '$\ddot{p}_z$', '$\dot\omega_{x}$', ... + '$\dot\omega_{y}$', '$\dot\omega_{z}$'}; +plt_indices = 1:6; + +for i = 1:length(plt_indices) + nexttile; + hold on; + grid; + plot(t_ctrl, ee_acc_eul(:, plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'k'); + plot(t_ctrl, ee_acc_mob(:, plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'r'); + % plot(t, ee_acc_sosml(:, plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'b'); + xlim([t_start, t_end]); + ylabel(ytitles(i), 'Interpreter', 'latex', 'FontSize', fs_lbl); + + % if i == 1 || i == 2 || i == 3 + % ylim([-1 1]); + % elseif i == 4 || i == 5 || i == 6 + % ylim([-2 2]); + % end + + if i == 3 + legend('Euler method', 'MOB estimation', 'SOSML estimation', 'FontName', font, 'FontSize', fs_lgd, 'interpreter', 'latex'); + end +end + +title(fig_ddx, 'Task Acceleration', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel(fig_ddx, 'Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); + +%% Pose Tracking Performance +% close all; +figure(); +fig_pose = tiledlayout(7, 1, "Padding", "compact", "TileSpacing", "compact"); +ytitles = {'$p_{ee} \ [m]$', '$\psi_{ee} \ [rad]$'}; +plt_indices = 1:7; + +for i = 1:length(plt_indices) + nexttile; + hold on; + grid; + plot(t_ctrl, ee_pose_des(:, plt_indices(i)), 'LineStyle', '--', 'LineWidth', 2 * lw, 'Color', 'k'); + plot(t_ctrl, ee_pose_mes(:, plt_indices(i)), 'LineStyle', '-.', 'LineWidth', lw, 'Color', 'r'); + xlim([t_start, t_end]); + + if i == 1 + ylabel(ytitles{mod(i-1, 2) + 1}, 'Interpreter', 'latex', 'FontSize', fs_lbl); + end + + if i == 1 + legend('Desired', 'Impedance control', 'Impedance control + DOB' , 'FontName', font, 'FontSize', fs_lgd, 'interpreter', 'latex'); + end +end + +% for i = 1:length(plt_indices) +% nexttile; +% hold on; +% grid; +% plot(t, ee_rpy_des(:, plt_indices(i)), 'LineStyle', '--', 'LineWidth', 2 * lw, 'Color', 'k'); +% plot(t, ee_rpy_mes(:, plt_indices(i)), 'LineStyle', '-.', 'LineWidth', lw, 'Color', 'r'); +% plot(t_dob, ee_rpy_mes_dob(:, plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'b'); +% % plot(t, fr_ee_rpy_mes(:, plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'b'); +% xlim([t_start, t_end]); +% +% if i == 1 +% ylabel(ytitles{mod(i-1, 2) + 1 + 1}, 'Interpreter', 'latex', 'FontSize', fs_lbl); +% end +% end + +title(fig_pose, 'Pose Tracking', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel(fig_pose, 'Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); + +%% Twist Tracking Performance +figure(); +fig_twist = tiledlayout(6, 1, "Padding", "compact", "TileSpacing", "compact"); +ytitles = {'$\dot{p}_{ee} \ [m/s]$', '$\omega_{ee} \ [rad/s]$'}; +plt_indices = 1:6; + +for i = 1:length(plt_indices) + nexttile; + hold on; + grid; + plot(t_ctrl, ee_vel_des(:, plt_indices(i)), 'LineStyle', '--', 'LineWidth', 2 * lw, 'Color', 'k'); + plot(t_ctrl, ee_vel_mes(:, plt_indices(i)), 'LineStyle', '-.', 'LineWidth', 1.5 * lw, 'Color', 'r'); + xlim([t_start, t_end]); + + if i == 1 || i == 4 + ylabel(ytitles{mod(i-1, 2) + 1}, 'Interpreter', 'latex', 'FontSize', fs_lbl); + end + + if i == 1 + legend('Desired', 'Measured', 'FontName', font, 'FontSize', fs_lgd, 'interpreter', 'latex'); + end +end + +title(fig_twist, 'Twist Tracking', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel(fig_twist, 'Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); + +%% Estimated disturbance +% close all; +figure(); +% ytitles = {'$\hat{F}_{ext} \ [N]$', '$\hat{T}_{ext} \ [N/m]$'}; + +nexttile; +hold on; +grid; +plot(t_ft, Fz_ft, 'LineStyle', '--', 'LineWidth', 1 * lw, 'Color', 'k'); +plot(t_ctrl, -1 * F_d_fr3(:, 3), 'LineStyle', '-', 'LineWidth', 2*lw, 'Color', '#EDB120'); +plot(t_ctrl, F_d_dob(:, 3), 'LineStyle', '-.', 'LineWidth', 2*lw, 'Color', '#0072BD'); +plot(t_ctrl, F_d_mob(:, 3), 'LineStyle', '-', 'LineWidth', 1 * lw, 'Color', '#D95319'); +% plot(t, F_d_sosml(:, 3), 'LineStyle', '-', 'LineWidth', 1 * lw, 'Color', 'g'); +xlim([t_start, t_end]); + +title('Task Disturbance Estimation', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel('Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); + +%% Joint torque disturbance estiamtion +% close all; +figure(); +fig_ddq = tiledlayout(7, 1, "Padding", "compact", "TileSpacing", "compact"); +ytitles = {'$\tau_1$', '$\tau_2$', '$\tau_3$', '$\tau_4$', '$\tau_5$', '$\tau_6$', '$\tau_7$',}; +plt_indices = 1:7; + +for i = 1:length(plt_indices) + nexttile; + hold on; + grid; + plot(t_ctrl, tau_d_dob(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'r'); + plot(t_ctrl, tau_d_mob(:,plt_indices(i)), 'LineStyle', '--', 'LineWidth', 1.5 * lw, 'Color', 'b'); + % plot(t, tau_d_sosml(:,plt_indices(i)), 'LineStyle', '--', 'LineWidth', 1.5 * lw, 'Color', 'g'); + % plot(t, tau_c(:,plt_indices(i)) + tau_g(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'g'); + % plot(t, tau_c(:,plt_indices(i)), 'LineStyle', '-', 'LineWidth', lw, 'Color', 'g'); + xlim([t_start, t_end]); + % ylim([-5 5]); + + ylabel(ytitles(plt_indices(i)), 'Interpreter', 'latex', 'FontSize', fs_lbl) + + if i == 1 + legend('MOB estimation', 'DOB estimation', 'MuJoCo', 'FontName', font, 'FontSize', fs_lgd, 'interpreter', 'latex'); + end +end + +title(fig_ddq, 'Joint Acceleration $[rad/s^2]$', 'FontSize', fs_title, 'FontName', font, 'Interpreter', 'latex'); +xlabel(fig_ddq, 'Time (sec)', 'Interpreter', 'latex', 'FontSize', fs_lbl, 'FontName', font); diff --git a/assets/model/double_pendulum.urdf b/assets/model/double_pendulum.urdf new file mode 100644 index 0000000000000000000000000000000000000000..15e89ccc59e480db54e192eeea6418c43b7064eb --- /dev/null +++ b/assets/model/double_pendulum.urdf @@ -0,0 +1,87 @@ +<?xml version="1.0" ?> +<robot name="double_pendulum"> + + <!-- Material Definitions --> + <material name="black"> + <color rgba="0.0 0.0 0.0 1.0" /> + </material> + <material name="blue"> + <color rgba="0.0 0.0 1.0 1.0" /> + </material> + <material name="red"> + <color rgba="1.0 0.0 0.0 1.0" /> + </material> + + <!-- Base link --> + <link name="base_link"/> + + <!-- First link --> + <link name="link1"> + <inertial> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <mass value="1.0"/> + <inertia ixx="0.03" ixy="0.0" ixz="0.0" iyy="0.04" iyz="0.0" izz="0.05"/> + </inertial> + <visual> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <geometry> + <box size="0.1 0.1 1.0"/> + </geometry> + <material name="blue"/> + </visual> + <collision> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <geometry> + <box size="0.1 0.1 1.0"/> + </geometry> + </collision> + </link> + + <!-- Joint connecting base to first link --> + <joint name="joint1" type="revolute"> + <parent link="base_link"/> + <child link="link1"/> + <origin xyz="0 0 1.5" rpy="-1.5708 0 0"/> + <axis xyz="1 0 0"/> + <limit effort="10.0" velocity="5.0" lower="-3.14" upper="3.14"/> + </joint> + + <!-- Second link --> + <link name="link2"> + <inertial> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <mass value="1.0"/> + <inertia ixx="0.07" ixy="0.0" ixz="0.0" iyy="0.06" iyz="0.0" izz="0.08"/> + </inertial> + <visual> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <geometry> + <box size="0.1 0.1 1.0"/> + </geometry> + <material name="red"/> + </visual> + <collision> + <origin xyz="0 0 0.5" rpy="0 0 0"/> + <geometry> + <box size="0.1 0.1 1.0"/> + </geometry> + </collision> + </link> + + <!-- Joint connecting first link to second link --> + <joint name="joint2" type="revolute"> + <parent link="link1"/> + <child link="link2"/> + <origin xyz="0.1 0 1.0" rpy="0 0 0"/> + <axis xyz="1 0 0"/> + <limit effort="10.0" velocity="5.0" lower="-3.14" upper="3.14"/> + </joint> + + <!-- TCP frame --> + <link name="tcp_link"/> + <joint name="tcp_joint" type="fixed"> + <origin rpy="0 0 0" xyz="0 0 1.0"/> + <parent link="link2"/> + <child link="tcp_link"/> + </joint> +</robot> diff --git a/cmake/ClangTools.cmake b/cmake/ClangTools.cmake new file mode 100644 index 0000000000000000000000000000000000000000..84b474014a4b3d49a3e4f1c79074bfdeb77d51be --- /dev/null +++ b/cmake/ClangTools.cmake @@ -0,0 +1,65 @@ +include(CMakeParseArguments) + +find_program(CLANG_FORMAT_PROG clang-format-7 DOC "'clang-format' executable") +if(CLANG_FORMAT_PROG AND NOT TARGET format) + add_custom_target(format) + add_custom_target(check-format) +endif() +find_program(CLANG_TIDY_PROG clang-tidy-7 DOC "'clang-tidy' executable") +if(CLANG_TIDY_PROG AND NOT TARGET tidy) + if(NOT CMAKE_EXPORT_COMPILE_COMMANDS) + message(WARNING "Invoke Catkin/CMake with '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON' + to generate compilation database for 'clang-tidy'.") + endif() + + add_custom_target(tidy) + add_custom_target(check-tidy) +endif() + +function(add_format_target _target) + if(NOT CLANG_FORMAT_PROG) + return() + endif() + cmake_parse_arguments(ARG "" "" "FILES" ${ARGN}) + + add_custom_target(format-${_target} + COMMAND ${CLANG_FORMAT_PROG} -i ${ARG_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + COMMENT "Formatting ${_target} source code with clang-format" + VERBATIM + ) + add_dependencies(format format-${_target}) + + add_custom_target(check-format-${_target} + COMMAND ${CLANG_FORMAT_PROG} -output-replacements-xml ${ARG_FILES} | grep "<replacement " > /dev/null && exit 1 || exit 0 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + COMMENT "Checking ${_target} code formatting with clang-format" + VERBATIM + ) + add_dependencies(check-format check-format-${_target}) +endfunction() + +function(add_tidy_target _target) + if(NOT CLANG_TIDY_PROG) + return() + endif() + cmake_parse_arguments(ARG "" "" "FILES;DEPENDS" ${ARGN}) + + add_custom_target(tidy-${_target} + COMMAND ${CLANG_TIDY_PROG} -fix -p=${CMAKE_BINARY_DIR} ${ARG_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + DEPENDS ${ARG_DEPENDS} + COMMENT "Running clang-tidy for ${_target}" + VERBATIM + ) + add_dependencies(tidy tidy-${_target}) + + add_custom_target(check-tidy-${_target} + COMMAND ${CLANG_TIDY_PROG} -p=${CMAKE_BINARY_DIR} ${ARG_FILES} | grep . && exit 1 || exit 0 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + DEPENDS ${ARG_DEPENDS} + COMMENT "Running clang-tidy for ${_target}" + VERBATIM + ) + add_dependencies(check-tidy check-tidy-${_target}) +endfunction() diff --git a/cmake/PepTools.cmake b/cmake/PepTools.cmake new file mode 100644 index 0000000000000000000000000000000000000000..1377a4c1e5db5ce2aeff48834ceec6ed42e029a6 --- /dev/null +++ b/cmake/PepTools.cmake @@ -0,0 +1,21 @@ +include(CMakeParseArguments) + +find_program(PEP_FORMAT_PROG pycodestyle DOC "'pycodestyle' executable") +if(PEP_FORMAT_PROG AND NOT TARGET pyformat) + add_custom_target(check-pyformat) +endif() + +function(add_pyformat_target _target) + if(NOT PEP_FORMAT_PROG) + return() + endif() + cmake_parse_arguments(ARG "" "" "FILES" ${ARGN}) + + add_custom_target(check-pyformat-${_target} + COMMAND ${PEP_FORMAT_PROG} ${ARG_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/.. + COMMENT "Checking ${_target} code formatting with pycodestyle" + VERBATIM + ) + add_dependencies(check-pyformat check-pyformat-${_target}) +endfunction() \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9d4025de473be6d24009f9b1855d44952d2e959c..98a4b631b84e4f6e33cc9bba1d0c86daf06f2850 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -2,45 +2,39 @@ # This builds common as a shared lib so it can be built as Nix package and # linked to the other binaries. -################################################################################ -## Set minimum required version of cmake, project name and compile options -################################################################################ +# --- Set minimum required version of cmake, project name and compile options cmake_minimum_required(VERSION 3.10) project(common) -# Set C++ standard +# --- Set C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -################################################################################ -## Find required CMake packages : pinocchio, casadi, catkin, ROS-related ... -################################################################################ +# --- Find required CMake packages : pinocchio, casadi, catkin, ROS-related ... find_package(pinocchio REQUIRED) find_package(casadi REQUIRED) find_package(Eigen3 REQUIRED NO_MODULE) -################################################################################ -## Find source and header files to create executable binary file -################################################################################ +# --- Find source and header files to create executable binary file file(GLOB_RECURSE SOURCES - controller/src/*.cpp - math/src/*.cpp - motion/src/*.cpp - robot/src/*.cpp - utilities/src/*.cpp + src/controller/*.cpp + src/math/*.cpp + src/motion/*.cpp + src/robot/*.cpp + src/utilities/*.cpp + # src/interface/*.cpp ) include_directories( - controller/include - math/include - motion/include - robot/include - utilities/include + include/controller + include/math + include/motion + include/robot + include/utilities + # include/interface ) -################################################################################ -## Define executable, Add source files & Link libraries -################################################################################ +# --- Define library, connecting source files & Link libraries add_library(common SHARED ${SOURCES}) target_link_libraries(common @@ -50,13 +44,14 @@ target_link_libraries(common ) target_include_directories(common - PUBLIC - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/controller/include> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/math/include> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/motion/include> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/robot/include> - $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/utilities/include> - ) +PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/controller> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/math> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/motion> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/robot> + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/utilities> + # $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/interface> +) install(TARGETS common EXPORT commonTargets @@ -68,18 +63,21 @@ install(EXPORT commonTargets NAMESPACE common:: DESTINATION lib/cmake/common) -install(DIRECTORY controller/include/ +install(DIRECTORY include/controller/ DESTINATION include) -install(DIRECTORY math/include/ +# install(DIRECTORY include/interface/ +# DESTINATION include) + +install(DIRECTORY include/math/ DESTINATION include) -install(DIRECTORY motion/include/ +install(DIRECTORY include/motion/ DESTINATION include) -install(DIRECTORY robot/include/ +install(DIRECTORY include/robot/ DESTINATION include) -install(DIRECTORY utilities/include/ +install(DIRECTORY include/utilities/ DESTINATION include) diff --git a/common/include/controller/DisturbanceObserver.hpp b/common/include/controller/DisturbanceObserver.hpp index 76c3f9f6b8220224fced25bfc269459f156c62fe..dc3caf48599429c8b05a5b152cc96334af9d3bda 100644 --- a/common/include/controller/DisturbanceObserver.hpp +++ b/common/include/controller/DisturbanceObserver.hpp @@ -5,9 +5,6 @@ #ifndef DISTURBANCE_OBSERVER_HPP_ #define DISTURBANCE_OBSERVER_HPP_ -/* C++ STL */ -#include <iostream> - /* Custom Headers */ #include "eigen_types.hpp" @@ -17,19 +14,26 @@ class DisturbanceObserver private: T dt_; // timestep VecX<T> fq_; // Q-filter cutoff-frequency [Hz] - VecX<T> Fd_hat_; // estimated force disturbance [N] + VecX<T> Fd_hat_; // estimated force disturbance [N, Nm] VecX<T> F_lhs_, F_lhs_prev_; // left-hand-side state of DOB VecX<T> F_rhs_, F_rhs_prev_; // right-hand-side state of DOB public: - DisturbanceObserver(const T & dt, const VecX<T> & fq); + DisturbanceObserver(const VecX<T> & fq); + + //* ----- SETTERS -------------------------------------------------------------------------------- + void set_parameters(const T & dt, const VecX<T> & fq) + { + dt_ = dt; + fq_ = fq; + } //* ----- METHODS -------------------------------------------------------------------------------- - // void update_previous_states() - // { - // F_lhs_prev_ = F_lhs_; - // F_rhs_prev_ = F_rhs_; - // }; + void update_previous_states() + { + F_lhs_prev_ = F_lhs_; + F_rhs_prev_ = F_rhs_; + }; //* ----- GETTERS -------------------------------------------------------------------------------- /** diff --git a/common/include/controller/ImpedanceController.hpp b/common/include/controller/ImpedanceController.hpp index 8a9a6af86ed8f2cd04e38a4a37310a7d9c7acf8d..94e1fd8887b72b55433f235d18eebe7126e3f36e 100644 --- a/common/include/controller/ImpedanceController.hpp +++ b/common/include/controller/ImpedanceController.hpp @@ -10,33 +10,36 @@ private: Vec6<T> x_0e_err_; // end-effector 6-DoF pose error Vec6<T> x_0e_err_prev_; // previous error Mat6<T> K_task_; // task-space stiffness matrix - Mat6<T> B_task_; // task-space damping matrix + Mat6<T> D_task_; // task-space damping matrix Vec6<T> F_task_; // computed task-space wrench from impedance controller Vec7<T> tau_task_; // joint-spce impedance torque Vec7<T> q_null_err_; // null-space joint configuration error Vec7<T> q_null_err_prev_; // previous error Mat7<T> K_null_; // null-space stiffness matrix - Mat7<T> B_null_; // null-space damping matrix + Mat7<T> D_null_; // null-space damping matrix Vec7<T> tau_null_; // computed null-space torque from impedance controller public: - ImpedanceController(const Mat6<T> & K_task, const Mat6<T> & B_task, const Mat7<T> & K_null, - const Mat7<T> & B_null); + ImpedanceController(); + //* ----- SETTERS -------------------------------------------------------------------------------- + void set_parameters(const Mat6<T> & K_task, const Mat6<T> & D_task, // + const Mat7<T> & K_null, const Mat7<T> & D_null); - //* ----- METHODS ---------------------------------------------------------------------------- *// + //* ----- METHODS -------------------------------------------------------------------------------- /** * @param q_null_des : desired null-space joint configuration * @param q_null_mes : measured null-space joint configuration */ void compute_null_error(const Vec7<T> & q_null_des, const Vec7<T> & q_null_mes); + void update_previous_states() { q_null_err_prev_ = q_null_err_; x_0e_err_prev_ = x_0e_err_; }; - //* ----- GETTERS ---------------------------------------------------------------------------- *// + //* ----- GETTERS -------------------------------------------------------------------------------- /** * @param dt : timestep * @param p_0e_des : desired end-effector position in {W} frame @@ -46,6 +49,7 @@ public: */ Vec6<T> get_pose_error(const Vec3<T> & p_0e_des, const Vec3<T> & p_0e_mes, const Quat<T> & q_0e_des, const Quat<T> & q_0e_mes); + Vec6<T> get_previous_pose_error(); /** @@ -55,13 +59,13 @@ public: /** * @param dq_null_err : Time-derivative of null-space joint configuration error - * @param J : end-effector Jacobian matrix - * @param Jt_pinv : pseudo-inverse of Jacobian transpose matrix + * @param J_t : end-effector Jacobian transpose matrix + * @param J_t_pinv : pseudo-inverse of Jacobian transpose matrix */ - Vec7<T> get_null_impedance_torque(const Vec7<T> & dq_null_err, const Eigen::MatrixXd & J, - const Eigen::MatrixXd & Jt_pinv); + Vec7<T> get_null_impedance_torque(const Vec7<T> & dq_null_err, const MatX<T> & J_t, + const MatX<T> & J_t_pinv); - //* ----- PRINTER ---------------------------------------------------------------------------- *// + //* ----- PRINTER -------------------------------------------------------------------------------- void print_pose_error(); void print_impedance_torque(); }; diff --git a/common/include/controller/MomentumObserver.hpp b/common/include/controller/MomentumObserver.hpp index a306c48fb3578e0a89315f93a74402eb9848e8dc..eccbc8b3a4f5433b707a24b99d3414e545c406e8 100644 --- a/common/include/controller/MomentumObserver.hpp +++ b/common/include/controller/MomentumObserver.hpp @@ -25,11 +25,18 @@ private: VecX<T> ddq_hat_; // n x 1 estimated joint acceleration [rad/s^2] public: - MomentumObserver(const T & dt, const VecX<T> & r_th, const VecX<T> & k); + MomentumObserver(const VecX<T> & r_th, const VecX<T> & k); - //* ----- SETTERS ---------------------------------------------------------------------------- *// + //* ----- SETTERS -------------------------------------------------------------------------------- void set_dynamics(const VecX<T> & tau, const MatX<T> & M, const MatX<T> & C, const VecX<T> & g); + void set_parameters(const T & dt, const VecX<T> & r_th, const VecX<T> & k) + { + dt_ = dt; + r_th_ = r_th; + K_.setIdentity().diagonal() = k; + } + //* ----- METHODS ---------------------------------------------------------------------------- *// /** * @brief compute residual vector (= low-pass filtered version of external torque) diff --git a/common/include/controller/SlidingModeObserver.hpp b/common/include/controller/SlidingModeObserver.hpp index 00f929c02da80e2c8be0cf7d0036e7c988344a4e..ebf1677f9f18668b1a1a1db66eff8cd25b2543b9 100644 --- a/common/include/controller/SlidingModeObserver.hpp +++ b/common/include/controller/SlidingModeObserver.hpp @@ -28,12 +28,23 @@ private: MatX<T> S1_, S2_, T1_, T2_; public: - SlidingModeObserver(const T & dt, const VecX<T> & s1, const VecX<T> & s2, const VecX<T> & t1, + SlidingModeObserver(const VecX<T> & s1, const VecX<T> & s2, const VecX<T> & t1, const VecX<T> & t2); //* ----- SETTERS ---------------------------------------------------------------------------- *// void set_dynamics(const VecX<T> & tau, const MatX<T> & M, const MatX<T> & C, const VecX<T> & g); + // ! this may cause compile-error + void set_parameters(const T & dt, const VecX<T> & s1, const VecX<T> & s2, const VecX<T> & t1, + const VecX<T> & t2) + { + dt_ = dt; + S1_.setIdentity().diagonal() = s1; + S2_.setIdentity().diagonal() = s2; + T1_.setIdentity().diagonal() = t1; + T2_.setIdentity().diagonal() = t2; + } + //* ----- METHODS ---------------------------------------------------------------------------- *// void compute_momentum_estimation(const VecX<T> & dq); // void update_previous_states(); diff --git a/common/include/interface/DRIMPC.hpp b/common/include/interface/DRIMPC.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/common/include/utilities/Timer.hpp b/common/include/utilities/Timer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..47591d7502861e4803d6f369654628dae36c2dac --- /dev/null +++ b/common/include/utilities/Timer.hpp @@ -0,0 +1,62 @@ +/*! @file Timer.hpp + * @brief Timer for measuring how long things take + */ + +#ifndef TIMER_HPP_ +#define TIMER_HPP_ + +#include <assert.h> +#include <stdint.h> +#include <time.h> + +class Timer +{ +private: + struct timespec start_time_; + +public: + /*! + * Construct and start timer + */ + explicit Timer() + { + start(); + }; + + /*! + * Start the timer + */ + void start() + { + clock_gettime(CLOCK_MONOTONIC, &start_time_); + } + + /*! + * Get milliseconds elapsed + */ + double getMillisec() + { + return (double)getNanosec() / 1.e6; + } + + /*! + *Get nanoseconds elapsed + */ + int64_t getNanosec() + { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (int64_t)(now.tv_nsec - start_time_.tv_nsec) + + 1'000'000'000 * (now.tv_sec - start_time_.tv_sec); + } + + /*! + * Get seconds elapsed + */ + double getSeconds() + { + return (double)getNanosec() / 1.e9; + } +}; + +#endif // TIMER_HPP_ \ No newline at end of file diff --git a/common/src/controller/DisturbanceObserver.cpp b/common/src/controller/DisturbanceObserver.cpp index 96270bf8ad809cfbac386054a70c0dfdda14cb10..fa500e3ae69d5e3fc4ee3c61afd174fe24b25e78 100644 --- a/common/src/controller/DisturbanceObserver.cpp +++ b/common/src/controller/DisturbanceObserver.cpp @@ -4,21 +4,31 @@ #include "DisturbanceObserver.hpp" +/* C++ STL */ #include <cmath> #include <iostream> using namespace std; template <typename T> -DisturbanceObserver<T>::DisturbanceObserver(const T & dt, const VecX<T> & fq) : dt_(dt), fq_(fq) +DisturbanceObserver<T>::DisturbanceObserver(const VecX<T> & fq) : fq_(fq) { - Fd_hat_.setZero(fq_.size()); - F_lhs_.setZero(fq_.size()); - F_lhs_prev_.setZero(fq_.size()); - F_rhs_.setZero(fq_.size()); - F_rhs_prev_.setZero(fq_.size()); + // FIXME: change this + // if ((fq_.array() <= 0).any()) + // { + // throw std::invalid_argument("fq_ must be positive and non-zero."); + // } + + int n = fq_.size(); + + Fd_hat_.setZero(n); + F_lhs_.setZero(n); + F_lhs_prev_.setZero(n); + F_rhs_.setZero(n); + F_rhs_prev_.setZero(n); }; +//* ----- GETTERS ---------------------------------------------------------------------------------- /** * @brief compute estimated force disturbance * @param F : n x 1 Cartesian force by Impedance control @@ -34,8 +44,24 @@ VecX<T> DisturbanceObserver<T>::get_force_disturbance(const VecX<T> & F, const M throw std::invalid_argument("F, Me, and ddx must have the same sizes"); } - VecX<T> wt; // wt = (2*PI*f)*t - wt = (2.0 * M_PI * fq_) * dt_; + /* prevent NaN */ + MatX<T> Me_safe = (Me.array().isFinite()).select(Me, 0); + + if ((F.array().isNaN()).any()) + { + throw std::runtime_error("Input F contains NaN values."); + } + if ((Me_safe.array().isNaN()).any()) + { + throw std::runtime_error("Input Me contains NaN values."); + } + if ((ddx.array().isNaN()).any()) + { + throw std::runtime_error("Input ddx contains NaN values."); + } + + VecX<T> wt = (2.0 * M_PI * fq_) * dt_; // wt = (2*PI*f)*t + wt = wt.cwiseMin(1e3); VecX<T> q = wt.array() / (1.0 + wt.array()); MatX<T> Q; @@ -48,9 +74,6 @@ VecX<T> DisturbanceObserver<T>::get_force_disturbance(const VecX<T> & F, const M Fd_hat_ = F_rhs_ - F_lhs_; - F_lhs_prev_ = F_lhs_; - F_rhs_prev_ = F_rhs_; - return Fd_hat_; } diff --git a/common/src/controller/ImpedanceController.cpp b/common/src/controller/ImpedanceController.cpp index ee5db752b9df003550f60079a8a78fdd2101bc28..0bcc66e28127962d1aa240592930157f777207b6 100644 --- a/common/src/controller/ImpedanceController.cpp +++ b/common/src/controller/ImpedanceController.cpp @@ -1,13 +1,15 @@ #include "ImpedanceController.hpp" +#include "orientation_utilities.hpp" + #include <iostream> +namespace ori = orient_utils; + using namespace std; template <typename T> -ImpedanceController<T>::ImpedanceController(const Mat6<T> & K_task, const Mat6<T> & B_task, - const Mat7<T> & K_null, const Mat7<T> & B_null) - : K_task_(K_task), B_task_(B_task), K_null_(K_null), B_null_(B_null) +ImpedanceController<T>::ImpedanceController() { x_0e_err_.setZero(); x_0e_err_prev_.setZero(); @@ -17,9 +19,25 @@ ImpedanceController<T>::ImpedanceController(const Mat6<T> & K_task, const Mat6<T q_null_err_.setZero(); q_null_err_prev_.setZero(); tau_null_.setZero(); + + K_task_.setIdentity(); + D_task_.setIdentity(); + K_null_.setIdentity(); + D_null_.setIdentity(); +} + +//* ----- SETTERS ---------------------------------------------------------------------------------- +template <typename T> +void ImpedanceController<T>::set_parameters(const Mat6<T> & K_task, const Mat6<T> & D_task, + const Mat7<T> & K_null, const Mat7<T> & D_null) +{ + K_task_ = K_task; + D_task_ = D_task; + K_null_ = K_null; + D_null_ = D_null; } -//* ----- METHODS ------------------------------------------------------------------------------ *// +//* ----- METHODS ---------------------------------------------------------------------------------- template <typename T> void ImpedanceController<T>::compute_null_error(const Vec7<T> & q_null_des, const Vec7<T> & q_null_mes) @@ -27,7 +45,7 @@ void ImpedanceController<T>::compute_null_error(const Vec7<T> & q_null_des, q_null_err_ = q_null_des - q_null_mes; } -//* ----- GETTERS ------------------------------------------------------------------------------ *// +//* ----- GETTERS ---------------------------------------------------------------------------------- template <typename T> Vec6<T> ImpedanceController<T>::get_pose_error(const Vec3<T> & p_0e_des, const Vec3<T> & p_0e_mes, const Quat<T> & q_0e_des, const Quat<T> & q_0e_mes) @@ -44,8 +62,10 @@ Vec6<T> ImpedanceController<T>::get_pose_error(const Vec3<T> & p_0e_des, const V q_new.coeffs() << q_0e_mes.coeffs(); } Quat<T> q_0e_err = q_new.inverse() * q_0e_des; + RotMat<T> R = ori::quaternionToRotationMatrix(q_new); x_0e_err_.tail(3) << q_0e_err.x(), q_0e_err.y(), q_0e_err.z(); - x_0e_err_.tail(3) << q_new * x_0e_err_.tail(3); + // x_0e_err_.tail(3) << q_new * x_0e_err_.tail(3); + x_0e_err_.tail(3) << R * x_0e_err_.tail(3); return x_0e_err_; } @@ -62,16 +82,16 @@ Vec6<T> ImpedanceController<T>::get_previous_pose_error() template <typename T> Vec6<T> ImpedanceController<T>::get_task_impedance_force(const Vec6<T> & dx_0e_err) { - return K_task_ * x_0e_err_ + B_task_ * dx_0e_err; + return K_task_ * x_0e_err_ + D_task_ * dx_0e_err; } template <typename T> Vec7<T> ImpedanceController<T>::get_null_impedance_torque(const Vec7<T> & dq_null_err, - const Eigen::MatrixXd & J, - const Eigen::MatrixXd & Jt_pinv) + const MatX<T> & J_t, + const MatX<T> & J_t_pinv) { - return (Eigen::MatrixXd::Identity(7, 7) - J.transpose() * Jt_pinv) * - (K_null_ * q_null_err_ - B_null_ * dq_null_err); + Mat7<T> I = Mat7<T>::Identity(); + return (I - J_t * J_t_pinv) * (K_null_ * q_null_err_ - D_null_ * dq_null_err); } //* ----- PRINTER ------------------------------------------------------------------------------ *// diff --git a/common/src/controller/MomentumObserver.cpp b/common/src/controller/MomentumObserver.cpp index 051e9ee794fa222e3953dd7ae1a26658c65a9254..23e66b275a0468d8de50cfcf4ec9924466112265 100644 --- a/common/src/controller/MomentumObserver.cpp +++ b/common/src/controller/MomentumObserver.cpp @@ -10,22 +10,22 @@ using namespace std; template <typename T> -MomentumObserver<T>::MomentumObserver(const T & dt, const VecX<T> & r_th, const VecX<T> & k) - : dt_(dt), r_th_(r_th) +MomentumObserver<T>::MomentumObserver(const VecX<T> & r_th, const VecX<T> & k) : r_th_(r_th) { - size_t nv = r_th_.size(); + int n = r_th_.size(); - tau_.setZero(nv); - M_.setZero(nv, nv); - C_.setZero(nv, nv); - g_.setZero(nv); - r_.setZero(nv); - ddq_hat_.setZero(nv); + tau_.setZero(n); + M_.setZero(n, n); + C_.setZero(n, n); + g_.setZero(n); + r_.setZero(n); + ddq_hat_.setZero(n); - K_.setIdentity(nv, nv); + K_.setIdentity(n, n); K_.diagonal() = k; } +//* ----- SETTERS ---------------------------------------------------------------------------------- template <typename T> void MomentumObserver<T>::set_dynamics(const VecX<T> & tau, const MatX<T> & M, const MatX<T> & C, const VecX<T> & g) diff --git a/common/src/controller/SlidingModeObserver.cpp b/common/src/controller/SlidingModeObserver.cpp index ef6beaa2065099701c08cf22408dab39eb6a50c3..d27921cf0c6adcff53e8f1af159a8e415a5eebd8 100644 --- a/common/src/controller/SlidingModeObserver.cpp +++ b/common/src/controller/SlidingModeObserver.cpp @@ -15,35 +15,27 @@ using namespace std; template <typename T> -SlidingModeObserver<T>::SlidingModeObserver(const T & dt, const VecX<T> & s1, const VecX<T> & s2, +SlidingModeObserver<T>::SlidingModeObserver(const VecX<T> & s1, const VecX<T> & s2, const VecX<T> & t1, const VecX<T> & t2) - : dt_(dt_) { // std::cout << std::setprecision(6); // std::cout << std::fixed; - size_t nv = s1.size(); - - tau_.setZero(nv); - M_.setZero(nv, nv); - C_.setZero(nv, nv); - g_.setZero(nv); - - x1_hat_.setZero(nv); - dx1_hat_.setZero(nv); - x2_hat_.setZero(nv); - dx2_hat_.setZero(nv); - - S1_.setIdentity(nv, nv); - S1_.diagonal() = s1; - - S2_.setIdentity(nv, nv); - S2_.diagonal() = s2; - - T1_.setIdentity(nv, nv); - T1_.diagonal() = t1; - - T2_.setIdentity(nv, nv); - T2_.diagonal() = t2; + int n = s1.size(); + + tau_.setZero(n); + M_.setZero(n, n); + C_.setZero(n, n); + g_.setZero(n); + + x1_hat_.setZero(n); + dx1_hat_.setZero(n); + x2_hat_.setZero(n); + dx2_hat_.setZero(n); + + S1_.setIdentity(n, n).diagonal() = s1; + S2_.setIdentity(n, n).diagonal() = s2; + T1_.setIdentity(n, n).diagonal() = t1; + T2_.setIdentity(n, n).diagonal() = t2; }; //* ----- SETTERS ------------------------------------------------------------------------------ *// @@ -72,6 +64,7 @@ void SlidingModeObserver<T>::compute_momentum_estimation(const VecX<T> & dq) throw std::invalid_argument("Input sizes do not match internal state size."); } + // ! this may cause NaN VecX<T> f = M_.inverse() * (tau_ - C_ * dq - g_); VecX<T> x1 = dq; diff --git a/common/src/interface/DRIMPC.cpp b/common/src/interface/DRIMPC.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a054433e665a94f2e4209933f3a663d911c08da6 --- /dev/null +++ b/common/src/interface/DRIMPC.cpp @@ -0,0 +1,3 @@ +/** + * @brief Disturbance-rejeccted Impedance Predictive Control (DRIMPC) + */ \ No newline at end of file diff --git a/flake.lock b/flake.lock index 63325e36a0e8d20f8482e34facdf03d65ab64e20..d4b0cf3054d1550d8b38b8f7479d60ab5140f4ed 100644 --- a/flake.lock +++ b/flake.lock @@ -138,11 +138,11 @@ }, "nixpkgs_2411": { "locked": { - "lastModified": 1737672001, - "narHash": "sha256-YnHJJ19wqmibLQdUeq9xzE6CjrMA568KN/lFPuSVs4I=", + "lastModified": 1738843498, + "narHash": "sha256-7x+Q4xgFj9UxZZO9aUDCR8h4vyYut4zPUvfj3i+jBHE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "035f8c0853c2977b24ffc4d0a42c74f00b182cd8", + "rev": "f5a32fa27df91dfc4b762671a0e0a859a8a0058f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 4ffcdd98fd4196dda84210f113b41c6ebd240e58..7a14afb18648772fa7152cb20aff45a296286044 100644 --- a/flake.nix +++ b/flake.nix @@ -12,10 +12,28 @@ outputs = inputs@{ self, ... }: let system = "x86_64-linux"; - + + franka-overrides = final: prev: { + rosPackages = prev.rosPackages // { + noetic = prev.rosPackages.noetic.overrideScope( finalPkg: prevPkg: { + libfranka = prevPkg.libfranka.overrideAttrs (old: rec { + version = "0.11.0"; + src = prev.fetchFromGitHub { + owner = "frankaemika"; + repo = "libfranka"; + rev = version; + fetchSubmodules=true; + sha256 = "sha256-ugzXWI4ss9+mwWoHR+0T22LZ+SKviJJRQEIDSDfbe/k="; + }; + }); + }); + }; + }; + overlays = [ inputs.nix-ros-overlay.overlays.default inputs.nixgl.overlay + franka-overrides ]; pkgs = import inputs.nixpkgs { @@ -27,7 +45,7 @@ }; rospkgs = pkgs.rosPackages.noetic; - + rosPackages = with rospkgs; [ ros-core catkin # for builds, probably not yet needed @@ -39,27 +57,38 @@ joy joy-teleop + interactive-markers + spacenav-node + rqt-reconfigure + dynamic-reconfigure + rqt-plot + # rviz # adding this induces nix develop error + # python-qt-binding + # qt-gui-core + # py-binding-tools + ## for impedance controller - franka-example-controllers - #franka-hw - #combined-robot-hw - #joint-limits-interface - #controller-interface - #actionlib + # franka-example-controllers + # franka-hw + # combined-robot-hw + # joint-limits-interface + # controller-interface + # actionlib ## standard - #control-msgs # needed for JointTrajInterface - #moveit-msgs + # control-msgs # needed for JointTrajInterface + # moveit-msgs franka-msgs urdf ]; - common = pkgs_2411.callPackage ./common { }; - fr3-impedance-controller = rospkgs.callPackage ./fr3_impedance_controller_real { - inherit common; - }; + fr3-custom-msgs = rospkgs.callPackage ./fr3_custom_msgs {}; + fr3-impedance-controller = rospkgs.callPackage ./fr3_impedance_controller_real { + inherit common fr3-custom-msgs; + }; + projectPackages = [ common @@ -72,6 +101,7 @@ pkgs.glfw pkgs.nixgl.nixGLIntel ]; + in { devShells.${system} = { @@ -83,6 +113,8 @@ #pkgs.python3Packages.pincas pkgs_2411.casadi pkgs_2411.pinocchio + pkgs.python311Packages.pyqt5 # for rqt_reconfigure + # pkgs.python311Packages.pandas ]; }) ]; diff --git a/fr3_custom_msgs/CMakeLists.txt b/fr3_custom_msgs/CMakeLists.txt index 0b32be8b651e169e8dc70d53567dc3f19892ee27..ce4e40edf6c11fb7c048154f46f5284277045aa5 100644 --- a/fr3_custom_msgs/CMakeLists.txt +++ b/fr3_custom_msgs/CMakeLists.txt @@ -2,16 +2,17 @@ cmake_minimum_required(VERSION 3.10) project(fr3_custom_msgs) find_package(catkin REQUIRED COMPONENTS + std_srvs std_msgs sensor_msgs geometry_msgs message_generation - std_srvs ) # --- Generate messages in the 'msg' folder add_message_files( FILES + ControllerState.msg MujocoCommand.msg MujocoSensor.msg ) @@ -20,16 +21,16 @@ add_message_files( # !! generate_messages() must be called before catkin_package() !! generate_messages( DEPENDENCIES + std_srvs std_msgs sensor_msgs geometry_msgs - std_srvs ) catkin_package(CATKIN_DEPENDS message_runtime + std_srvs std_msgs sensor_msgs geometry_msgs - std_srvs ) \ No newline at end of file diff --git a/fr3_custom_msgs/msg/ControllerState.msg b/fr3_custom_msgs/msg/ControllerState.msg new file mode 100644 index 0000000000000000000000000000000000000000..36a6859bb1679838538548b50d4f180a01aeab16 --- /dev/null +++ b/fr3_custom_msgs/msg/ControllerState.msg @@ -0,0 +1,18 @@ +std_msgs/Header header +float64[7] ddq_eul # joint accel by Euler method +float64[7] ddq_mob # ........... estimation by MOB +float64[7] ddq_sosml # ........... estimation by SOSML +float64[7] tau_dist_dob # joint torque disturbance estimation by DOB +float64[7] tau_dist_mob # ................................... by MOB +float64[7] tau_dist_sosml # ................................... by SOSML +geometry_msgs/Wrench F_dist_franka # wrench disturbance estimation from franka (world frame) +geometry_msgs/Wrench F_dist_dob # ............................. by DOB +geometry_msgs/Wrench F_dist_mob # ............................. by MOB +geometry_msgs/Wrench F_dist_sosml # ............................. by SOSML +geometry_msgs/Pose ee_pose_world_des # end-effector pose reference (world frame) +geometry_msgs/Pose ee_pose_world_mes # ................. measurement +geometry_msgs/Twist ee_vel_world_des # end-effector twist reference (world frame) +geometry_msgs/Twist ee_vel_world_mes # .................. measurement +geometry_msgs/Accel ee_acc_world_eul # task accel by Euler method (world frame) +geometry_msgs/Accel ee_acc_world_mob # .......... estimation by MOB +geometry_msgs/Accel ee_acc_world_sosml # .......... estimation by SOSML diff --git a/fr3_impedance_controller_real/CMakeLists.txt b/fr3_impedance_controller_real/CMakeLists.txt index 34e464adad3724270962fbf824cb520014d94e51..534c72f95b20ef452b68f6108bb18f4f77f3cb9d 100644 --- a/fr3_impedance_controller_real/CMakeLists.txt +++ b/fr3_impedance_controller_real/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required(VERSION 3.4) -project(fr3_impedance_controller_real) +project(franka_example_controllers) set(CMAKE_BUILD_TYPE Release) -# set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -12,7 +11,6 @@ find_package(catkin REQUIRED COMPONENTS eigen_conversions franka_hw franka_gripper - franka_example_controllers geometry_msgs hardware_interface joint_limits_interface @@ -25,23 +23,28 @@ find_package(catkin REQUIRED COMPONENTS rospy urdf visualization_msgs - sensor_msgs ) +# --- Add dependencies find_package(Eigen3 REQUIRED) find_package(Franka 0.9.0 QUIET) if(NOT Franka_FOUND) find_package(Franka 0.8.0 REQUIRED) endif() -#add_message_files(FILES -# JointTorqueComparison.msg -#) +# @Jeong : This should be included, otherwise, linking error happen (2025.02.07) +find_package(pinocchio REQUIRED) +find_package(common REQUIRED) +find_package(fr3_custom_msgs REQUIRED) + +# add_message_files(FILES +# JointTorqueComparison.msg +# ) generate_messages() generate_dynamic_reconfigure_options( - cfg/compliance_param.cfg + cfg/controller_param.cfg ) catkin_package( @@ -53,7 +56,6 @@ catkin_package( eigen_conversions franka_hw franka_gripper - franka_example_controllers geometry_msgs hardware_interface joint_limits_interface @@ -65,15 +67,14 @@ catkin_package( roscpp urdf visualization_msgs - sensor_msgs DEPENDS Franka ) -add_library(${PROJECT_NAME} - src/fr3_impedance_controller_real.cpp +add_library(franka_example_controllers + src/cartesian_impedance_example_controller.cpp ) -add_dependencies(${PROJECT_NAME} +add_dependencies(franka_example_controllers ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ${PROJECT_NAME}_generate_messages_cpp @@ -81,24 +82,45 @@ add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_gencfg ) -target_link_libraries(${PROJECT_NAME} PUBLIC +target_link_libraries(franka_example_controllers PUBLIC ${Franka_LIBRARIES} ${catkin_LIBRARIES} + # @Jeong : This should be included, otherwise, linking error happen (2025.02.07) + pinocchio::pinocchio + common::common ) -target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC +target_include_directories(franka_example_controllers SYSTEM PUBLIC ${Franka_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIRS} ${catkin_INCLUDE_DIRS} ) -target_include_directories(${PROJECT_NAME} PUBLIC + +target_include_directories(franka_example_controllers PUBLIC include - ${CMAKE_CURRENT_SOURCE_DIR}/../common/utilities/include - ${CMAKE_CURRENT_SOURCE_DIR}/../common/math/include ) +## @Jeongwoo : comment following lines cause they looks not necessary right now +# add_executable(teleop_gripper_node +# src/teleop_gripper_node.cpp +# ) +# target_include_directories(teleop_gripper_node PUBLIC +# ${catkin_INCLUDE_DIRS} +# ) +# target_link_libraries(teleop_gripper_node PUBLIC +# ${Franka_LIBRARIES} +# ${catkin_LIBRARIES} +# ) +# add_dependencies(teleop_gripper_node +# ${${PROJECT_NAME}_EXPORTED_TARGETS} +# ${catkin_EXPORTED_TARGETS} +# ${PROJECT_NAME}_generate_messages_cpp +# ${PROJECT_NAME}_gencpp +# ${PROJECT_NAME}_gencfg +# ) + ## Installation -install(TARGETS ${PROJECT_NAME} +install(TARGETS franka_example_controllers ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} @@ -112,10 +134,16 @@ install(DIRECTORY launch install(DIRECTORY config DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) -install(FILES fr3_impedance_controller_real_plugin.xml +install(FILES franka_example_controllers_plugin.xml DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} ) +## @Jeong : comment following lines cause these scripts are not necessary for this project +# catkin_install_python( +# PROGRAMS scripts/interactive_marker.py scripts/move_to_start.py scripts/dual_arm_interactive_marker.py +# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +# ) + ## Tools include(${CMAKE_CURRENT_LIST_DIR}/../cmake/ClangTools.cmake OPTIONAL RESULT_VARIABLE CLANG_TOOLS @@ -125,8 +153,6 @@ if(CLANG_TOOLS) file(GLOB_RECURSE HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h - ${CMAKE_CURRENT_SOURCE_DIR}/../common/utilities/include/*.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/../common/math/include/*.hpp ) add_format_target(franka_example_controllers FILES ${SOURCES} ${HEADERS}) add_tidy_target(franka_example_controllers @@ -138,7 +164,8 @@ endif() include(${CMAKE_CURRENT_LIST_DIR}/../cmake/PepTools.cmake OPTIONAL RESULT_VARIABLE PEP_TOOLS ) -if(PEP_TOOLS) - file(GLOB_RECURSE PYSOURCES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py) - add_pyformat_target(franka_control FILES ${PYSOURCES}) -endif() +## @Jeong : comment following lines cause these scripts are not necessary for this project +# if(PEP_TOOLS) +# file(GLOB_RECURSE PYSOURCES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py) +# add_pyformat_target(franka_control FILES ${PYSOURCES}) +# endif() diff --git a/fr3_impedance_controller_real/bak/CMakeLists_bak.txt b/fr3_impedance_controller_real/bak/CMakeLists_bak.txt new file mode 100644 index 0000000000000000000000000000000000000000..34e464adad3724270962fbf824cb520014d94e51 --- /dev/null +++ b/fr3_impedance_controller_real/bak/CMakeLists_bak.txt @@ -0,0 +1,144 @@ +cmake_minimum_required(VERSION 3.4) +project(fr3_impedance_controller_real) + +set(CMAKE_BUILD_TYPE Release) +# set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(catkin REQUIRED COMPONENTS + controller_interface + dynamic_reconfigure + eigen_conversions + franka_hw + franka_gripper + franka_example_controllers + geometry_msgs + hardware_interface + joint_limits_interface + tf + tf_conversions + message_generation + pluginlib + realtime_tools + roscpp + rospy + urdf + visualization_msgs + sensor_msgs +) + +find_package(Eigen3 REQUIRED) +find_package(Franka 0.9.0 QUIET) +if(NOT Franka_FOUND) + find_package(Franka 0.8.0 REQUIRED) +endif() + +#add_message_files(FILES +# JointTorqueComparison.msg +#) + +generate_messages() + +generate_dynamic_reconfigure_options( + cfg/compliance_param.cfg +) + +catkin_package( + INCLUDE_DIRS include + LIBRARIES franka_example_controllers + CATKIN_DEPENDS + controller_interface + dynamic_reconfigure + eigen_conversions + franka_hw + franka_gripper + franka_example_controllers + geometry_msgs + hardware_interface + joint_limits_interface + tf + tf_conversions + message_runtime + pluginlib + realtime_tools + roscpp + urdf + visualization_msgs + sensor_msgs + DEPENDS Franka +) + +add_library(${PROJECT_NAME} + src/fr3_impedance_controller_real.cpp +) + +add_dependencies(${PROJECT_NAME} + ${${PROJECT_NAME}_EXPORTED_TARGETS} + ${catkin_EXPORTED_TARGETS} + ${PROJECT_NAME}_generate_messages_cpp + ${PROJECT_NAME}_gencpp + ${PROJECT_NAME}_gencfg +) + +target_link_libraries(${PROJECT_NAME} PUBLIC + ${Franka_LIBRARIES} + ${catkin_LIBRARIES} +) + +target_include_directories(${PROJECT_NAME} SYSTEM PUBLIC + ${Franka_INCLUDE_DIRS} + ${EIGEN3_INCLUDE_DIRS} + ${catkin_INCLUDE_DIRS} +) +target_include_directories(${PROJECT_NAME} PUBLIC + include + ${CMAKE_CURRENT_SOURCE_DIR}/../common/utilities/include + ${CMAKE_CURRENT_SOURCE_DIR}/../common/math/include +) + +## Installation +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) +install(DIRECTORY include/${PROJECT_NAME}/ + DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} +) +install(DIRECTORY launch + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) +install(DIRECTORY config + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) +install(FILES fr3_impedance_controller_real_plugin.xml + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} +) + +## Tools +include(${CMAKE_CURRENT_LIST_DIR}/../cmake/ClangTools.cmake OPTIONAL + RESULT_VARIABLE CLANG_TOOLS +) +if(CLANG_TOOLS) + file(GLOB_RECURSE SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) + file(GLOB_RECURSE HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/../common/utilities/include/*.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/../common/math/include/*.hpp + ) + add_format_target(franka_example_controllers FILES ${SOURCES} ${HEADERS}) + add_tidy_target(franka_example_controllers + FILES ${SOURCES} + DEPENDS franka_example_controllers + ) +endif() + +include(${CMAKE_CURRENT_LIST_DIR}/../cmake/PepTools.cmake OPTIONAL + RESULT_VARIABLE PEP_TOOLS +) +if(PEP_TOOLS) + file(GLOB_RECURSE PYSOURCES ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py) + add_pyformat_target(franka_control FILES ${PYSOURCES}) +endif() diff --git a/fr3_impedance_controller_real/bak/cartesian_impedance_mpc.launch b/fr3_impedance_controller_real/bak/cartesian_impedance_mpc.launch new file mode 100644 index 0000000000000000000000000000000000000000..a11b1721c730436099ae15eec180eff7f5533c8e --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_impedance_mpc.launch @@ -0,0 +1,16 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + + <arg name="linear_gain" default="0.03" /> + <arg name="angular_gain" default="0.05" /> + + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + + + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_impedance_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/franka_description_with_marker.rviz"/> + <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" required="false" /> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_pose_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5a3f6a9571505f09cafb1ee66a030a7b4dd282a --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_controller.cpp @@ -0,0 +1,198 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_pose_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> +#include <geometry_msgs/PoseArray.h> +#include <tf2_geometry_msgs/tf2_geometry_msgs.h> + + +namespace franka_example_controllers { + +bool CartesianPoseController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) { + ROS_ERROR( + "CartesianPoseExampleController: Could not get Cartesian Pose " + "interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("CartesianPoseExampleController: Could not get parameter arm_id"); + return false; + } + + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("CartesianPoseExampleController: Could not get state interface from hardware"); + return false; + } + + // try { + // auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + // std::array<double, 7> q_start{{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + // for (size_t i = 0; i < q_start.size(); i++) { + // if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + // ROS_ERROR_STREAM( + // "CartesianPoseExampleController: Robot is not in the expected starting position for " + // "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " + // "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); + // return false; + // } + // } + // } catch (const hardware_interface::HardwareInterfaceException& e) { + // ROS_ERROR_STREAM( + // "CartesianPoseExampleController: Exception getting state handle: " << e.what()); + // return false; + // } + + single_pos_subscriber = node_handle.subscribe( + "/diffusion_policy_cartesian_pose", 1, + &CartesianPoseController::singlePosCallback, this); + + return true; +} + +void CartesianPoseController::starting(const ros::Time& /* time */) { + initial_pose = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "initial_pose = [" << initial_pose[12] << ", " << initial_pose[13] << ", " << initial_pose[14] << "]" << std::endl; +} + +void CartesianPoseController::singlePosCallback(const geometry_msgs::Pose::ConstPtr& msg) { + new_pose = *msg; + is_single_pos_received = true; + last_msg_time = ros::Time::now(); +} + + +//1000Hz +void CartesianPoseController::update(const ros::Time& time , + const ros::Duration& period) { + if (is_single_pos_received && (ros::Time::now() - last_msg_time).toSec() > 0.2) { + is_single_pos_received = false; + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + } + + if (is_single_pos_received) { + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "current_pose_tcp = [" << current_pose_tcp[12] << ", " << current_pose_tcp[13] << ", " << current_pose_tcp[14] << "]" << std::endl; + std::cout << "new_pose = [" << new_pose.position.x << ", " << new_pose.position.y << ", " << new_pose.position.z << "]" << std::endl; + + // calculate current velocity, acceleration and jerk + std::array<double, 3> current_vel = {(new_pose.position.x - current_pose_tcp[12]) / traj_step_time_, + (new_pose.position.y - current_pose_tcp[13]) / traj_step_time_, + (new_pose.position.z - current_pose_tcp[14]) / traj_step_time_,}; + std::array<double, 3> current_acc = {(current_vel[0] - old_vel[0]) / traj_step_time_, + (current_vel[1] - old_vel[1]) / traj_step_time_, + (current_vel[2] - old_vel[2]) / traj_step_time_,}; + std::array<double, 3> current_jerk = {(current_acc[0] - old_acc[0]) / traj_step_time_, + (current_acc[1] - old_acc[1]) / traj_step_time_, + (current_acc[2] - old_acc[2]) / traj_step_time_,}; + + //jerk check + double jerk = sqrt(pow(current_jerk[0], 2) + pow(current_jerk[1], 2) + pow(current_jerk[2], 2)); + int sign = 0; + if (fabs(jerk) > MAX_JERK) { + ROS_WARN_THROTTLE(1.0, "Jerk exceeds the limit."); + for (int i = 0; i <3; i++) { + if (fabs(current_jerk[i]) > MAX_JERK) { + sign = (current_jerk[i] > 0) ? 1 : -1; + current_acc[i] = old_acc[i] + sign * MAX_JERK * traj_step_time_; + current_vel[i] = old_vel[i] + current_acc[i] * traj_step_time_; + } + } + } + + // acceleration check + double acc = sqrt(pow(current_acc[0], 2) + pow(current_acc[1], 2) + pow(current_acc[2], 2)); + if(fabs(acc) > MAX_ACC) { + ROS_WARN_THROTTLE(1.0, "Acceleration exceeds the limit."); + for(int i = 0; i < 3; i++) { + if (fabs(current_acc[i]) > MAX_ACC) { + sign = (current_acc[i] > 0) ? 1 : -1; + current_vel[i] = old_vel[i] + sign * MAX_ACC * traj_step_time_; + } + } + } + + // velocity check + double vel = sqrt(pow(current_vel[0], 2) + pow(current_vel[1], 2) + pow(current_vel[2], 2)); + if(vel > MAX_VEL) { + ROS_WARN_THROTTLE(1.0, "Velocity exceeds the limit."); + for(int i = 0; i < 3; i++) { + if(fabs(current_vel[i]) > MAX_VEL) { + double sign = (current_vel[i] > 0) ? 1 : -1; + if(i == 0) + { + new_pose.position.x = current_pose_tcp[12] + sign * MAX_VEL * traj_step_time_; + } + else if (i == 1) + { + new_pose.position.y = current_pose_tcp[13] + sign * MAX_VEL * traj_step_time_; + } + else // i == 2 + { + new_pose.position.z = current_pose_tcp[14] + sign * MAX_VEL * traj_step_time_; + } + } + } + } + else { + // update new pose with (limited) velocity + new_pose.position.x = current_pose_tcp[12] + current_vel[0] * traj_step_time_; + new_pose.position.y = current_pose_tcp[13] + current_vel[1] * traj_step_time_; + new_pose.position.z = current_pose_tcp[14] + current_vel[2] * traj_step_time_; + } + + double dx = (new_pose.position.x - current_pose_tcp[12]) * update_step_size_; + double dy = (new_pose.position.y - current_pose_tcp[13]) * update_step_size_; + double dz = (new_pose.position.z - current_pose_tcp[14]) * update_step_size_; + + // set new pose + current_pose_tcp[12] += dx; + current_pose_tcp[13] += dy; + current_pose_tcp[14] += dz; + // print current_pose_ + // ROS_INFO("current_pose_ = [%f, %f, %f]", current_pose_[12], current_pose_[13], current_pose_[14]); + cartesian_pose_handle_->setCommand(current_pose_tcp); + + // update old values + old_vel = current_vel; + old_acc = current_acc; + + COUNT += 1; + std::cout << "COUNT = " << COUNT << std::endl; + } + else { + ROS_WARN_THROTTLE(1.0, "No single pose msg received."); + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + cartesian_pose_handle_->setCommand(current_pose_tcp); + } +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianPoseController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_controller.h b/fr3_impedance_controller_real/bak/cartesian_pose_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..8c270bde1c81506125e8fc5cbb86e114b0303368 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_controller.h @@ -0,0 +1,54 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> +#include <geometry_msgs/PoseArray.h> + +namespace franka_example_controllers { + +class CartesianPoseController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + franka_hw::FrankaPoseCartesianInterface* cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + double elapsed_time; + std::array<double, 16> initial_pose{}; + std::array<double, 16> current_pose_tcp{}; + + std::array<double, 3> old_vel{0.0, 0.0, 0.0}; + std::array<double, 3> old_acc{0.0, 0.0, 0.0}; + + const double traj_step_time_ = 0.1; + const double update_step_size_ = 0.001; + const double MAX_VEL = 1.7; //1.7 + const double MAX_ACC = 6; //13 + const double MAX_JERK = 500.0; //6500 + + int COUNT = 0; + + ros::Subscriber single_pos_subscriber; + void singlePosCallback(const geometry_msgs::Pose::ConstPtr& msg); + geometry_msgs::Pose new_pose; + bool is_single_pos_received = false; + ros::Time last_msg_time; + +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_controller.launch b/fr3_impedance_controller_real/bak/cartesian_pose_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..dc62a60d56c98f762be1a1026134d010e245160c --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_controller.launch @@ -0,0 +1,12 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <arg name="linear_gain" default="0.03" /> + <arg name="angular_gain" default="0.05" /> + <arg name="load_gripper" default="true" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_pose_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a916ed629abbe55c16a58b6bd4abec0ae16024a1 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_pose_example_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool CartesianPoseExampleController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) { + ROS_ERROR( + "CartesianPoseExampleController: Could not get Cartesian Pose " + "interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("CartesianPoseExampleController: Could not get parameter arm_id"); + return false; + } + + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("CartesianPoseExampleController: Could not get state interface from hardware"); + return false; + } + + try { + auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + std::array<double, 7> q_start{{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Robot is not in the expected starting position for " + "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " + "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); + return false; + } + } + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Exception getting state handle: " << e.what()); + return false; + } + + return true; +} + +void CartesianPoseExampleController::starting(const ros::Time& /* time */) { + initial_pose_ = cartesian_pose_handle_->getRobotState().O_T_EE_d; + elapsed_time_ = ros::Duration(0.0); +} + +void CartesianPoseExampleController::update(const ros::Time& /* time */, + const ros::Duration& period) { + elapsed_time_ += period; + + double radius = 0.15; + double angle = M_PI / 4 * (1 - std::cos(M_PI / 5.0 * elapsed_time_.toSec())); + double delta_x = radius * std::sin(angle); + double delta_z = radius * (std::cos(angle) - 1); + std::array<double, 16> new_pose = initial_pose_; + new_pose[12] -= delta_x; + new_pose[14] -= delta_z; + cartesian_pose_handle_->setCommand(new_pose); +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianPoseExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.h b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..e712c7a88c301a531ac214ecb09ec5ad7ccab831 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.h @@ -0,0 +1,34 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> + +namespace franka_example_controllers { + +class CartesianPoseExampleController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + franka_hw::FrankaPoseCartesianInterface* cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + ros::Duration elapsed_time_; + std::array<double, 16> initial_pose_{}; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.launch b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..a619d53bd7183ad7ad75e3843c0d51dab0afe2ab --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_pose_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_pose_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0555c2201fce191d2d39d07691f42aa9c034dff1 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.cpp @@ -0,0 +1,146 @@ +// Copyright (c) 2023 Franka Robotics GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_sinpose_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers +{ +bool CartesianSinPoseExampleController::init(hardware_interface::RobotHW * robot_hardware, + ros::NodeHandle & node_handle) +{ + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) + { + ROS_ERROR( + "CartesianSinPoseExampleController: Could not get Cartesian Pose " + "interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) + { + ROS_ERROR("CartesianSinPoseExampleController: Could not get parameter arm_id"); + return false; + } + + try + { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } + catch (const hardware_interface::HardwareInterfaceException & e) + { + ROS_ERROR_STREAM( + "CartesianSinPoseExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) + { + ROS_ERROR("CartesianSinPoseExampleController: Could not get state interface from hardware"); + return false; + } + +// try +// { +// auto state_handle = state_interface->getHandle(arm_id + "_robot"); + +// std::array<double, 7> q_start{ { 0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4 } }; +// for (size_t i = 0; i < q_start.size(); i++) +// { +// if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) +// { +// ROS_ERROR_STREAM( +// "CartesianSinPoseExampleController: Robot is not in the expected starting position for " +// "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " +// "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); +// return false; +// } +// } +// } +// catch (const hardware_interface::HardwareInterfaceException & e) +// { +// ROS_ERROR_STREAM( +// "CartesianSinPoseExampleController: Exception getting state handle: " << e.what()); +// return false; +// } + + return true; +} + +void CartesianSinPoseExampleController::starting(const ros::Time & /* time */) +{ + initial_pose_ = cartesian_pose_handle_->getRobotState().O_T_EE_d; + elapsed_time_ = ros::Duration(0.0); +} + +void CartesianSinPoseExampleController::update(const ros::Time & /* time */, + const ros::Duration & period) +{ + elapsed_time_ += period; + + // double radius = 0.15; + // double angle = M_PI / 4 * (1 - std::cos(M_PI / 5.0 * elapsed_time_.toSec())); + // double delta_x = radius * std::sin(angle); + // double delta_z = radius * (std::cos(angle) - 1); + std::array<double, 16> new_pose = initial_pose_; + // new_pose[12] -= delta_x; + // new_pose[14] -= delta_z; + + double Tp = 2.0; // period = 2 [sec] + double fp = 1 / Tp; // frequency = 0.5 [Hz] + double delta = 0.05; // displacement = 0.05 [m] + + double t1 = 1.0; + double t2 = 6.0; + double t3 = 11.0; + + + if (elapsed_time_.toSec() >= t1 && elapsed_time_.toSec() < t1 + 4.0) + { + new_pose[12] = + initial_pose_[12] + 0.5 * delta * (1 - std::cos(2 * M_PI * fp * (elapsed_time_.toSec() - t1))); + } + else if (elapsed_time_.toSec() >= t1 + 4.0 && elapsed_time_.toSec() < t2) + { + new_pose = initial_pose_; + } + else if (elapsed_time_.toSec() >= t2 && elapsed_time_.toSec() < t2 + 4.0) + { + new_pose[13] = + initial_pose_[13] + 0.5 * delta * (1 - std::cos(2 * M_PI * fp * (elapsed_time_.toSec() - t2))); + } + else if (elapsed_time_.toSec() >= t2 + 4.0 && elapsed_time_.toSec() < t3) + { + new_pose = initial_pose_; + } + else if (elapsed_time_.toSec() >= t3 && elapsed_time_.toSec() < t3 + 4.0) + { + new_pose[14] = + initial_pose_[14] + 0.5 * delta * (1 - std::cos(2 * M_PI * fp * (elapsed_time_.toSec() - t3))); + } + else + { + new_pose = initial_pose_; + } + std::cout << "px: " << new_pose[12] << " py: " << new_pose[13] << " pz: " << new_pose[14] << std::endl; + + cartesian_pose_handle_->setCommand(new_pose); +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianSinPoseExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.h b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..559ccd783014cb3d7364c7ad4f6b78a8c7f391bb --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.h @@ -0,0 +1,35 @@ +// Copyright (c) 2023 Franka Robotics GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> + +namespace franka_example_controllers +{ +class CartesianSinPoseExampleController : + public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> +{ +public: + bool init(hardware_interface::RobotHW * robot_hardware, ros::NodeHandle & node_handle) override; + void starting(const ros::Time &) override; + void update(const ros::Time &, const ros::Duration & period) override; + +private: + franka_hw::FrankaPoseCartesianInterface * cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + ros::Duration elapsed_time_; + std::array<double, 16> initial_pose_{}; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.launch b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..1ff5cfb431a21caa9fde46c975f156f91ef9162a --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_sinpose_controller.launch @@ -0,0 +1,12 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <arg name="linear_gain" default="0.03" /> + <arg name="angular_gain" default="0.05" /> + <arg name="load_gripper" default="true" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_sinpose_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_traj_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d08b6c7078df46d2f1d404bc9970acaccce36840 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_controller.cpp @@ -0,0 +1,214 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_traj_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> +#include <geometry_msgs/PoseArray.h> +#include <tf2_geometry_msgs/tf2_geometry_msgs.h> + + +namespace franka_example_controllers { + +bool CartesianTrajController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) { + ROS_ERROR( + "CartesianPoseExampleController: Could not get Cartesian Pose " + "interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("CartesianPoseExampleController: Could not get parameter arm_id"); + return false; + } + + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("CartesianPoseExampleController: Could not get state interface from hardware"); + return false; + } + + // Initialize the pose array subscriber + traj_subscriber = node_handle.subscribe( + "/diffusion_policy_cartesian_pose_traj", 1, + &CartesianTrajController::trajCallback, this); + + return true; +} + +void CartesianTrajController::starting(const ros::Time& /* time */) { + initial_pose = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "initial_pose = [" << initial_pose[12] << ", " << initial_pose[13] << ", " << initial_pose[14] << "]" << std::endl; +} + +//10Hz +void CartesianTrajController::trajCallback(const geometry_msgs::PoseArray::ConstPtr& msg) { + new_traj = *msg; + is_traj_received = true; + last_msg_time = ros::Time::now(); +} + +//1000Hz +void CartesianTrajController::update(const ros::Time& time , + const ros::Duration& period) { + if (is_traj_received && (ros::Time::now() - last_msg_time).toSec() > traj_step_time * 2) { + is_traj_received = false; + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + ROS_WARN_THROTTLE(1.0, "PoseArray msg stopped streaming."); + } + + if (is_traj_received) { + // if (fmod(COUNT * update_step_size, control_horizon * traj_step_time) == 0) { + // traj_to_control = new_traj; + // } + // traj_to_control = new_traj; + + + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "current_pose_tcp = [" << current_pose_tcp[12] << ", " << current_pose_tcp[13] << ", " << current_pose_tcp[14] << "]" << std::endl; + + // find the index of the closest pose in the trajectory and add a offset to it + std::vector<double> current_tcp_pos_vec; + current_tcp_pos_vec.assign(current_pose_tcp.begin()+12, current_pose_tcp.begin()+15); + std::vector<double> distances = calc_distances(new_traj, current_tcp_pos_vec); + auto min_value = std::min_element(distances.begin(), distances.end()); + int min_index = std::distance(distances.begin(), min_value); + std::cout << "min_index = " << min_index << std::endl; + int control_index = std::min(min_index+control_horizon, static_cast<int>(new_traj.poses.size())-1); + std::cout << "control_index = " << control_index << std::endl; + new_pose = new_traj.poses[control_index]; + std::cout << "new_pose = [" << new_pose.position.x << ", " << new_pose.position.y << ", " << new_pose.position.z << "]" << std::endl; + //calculate the distance between the current pose + + // calculate current velocity, acceleration and jerk + std::array<double, 3> current_vel = {(new_pose.position.x - current_pose_tcp[12]) / traj_step_time, + (new_pose.position.y - current_pose_tcp[13]) / traj_step_time, + (new_pose.position.z - current_pose_tcp[14]) / traj_step_time,}; + std::array<double, 3> current_acc = {(current_vel[0] - old_vel[0]) / traj_step_time, + (current_vel[1] - old_vel[1]) / traj_step_time, + (current_vel[2] - old_vel[2]) / traj_step_time,}; + std::array<double, 3> current_jerk = {(current_acc[0] - old_acc[0]) / traj_step_time, + (current_acc[1] - old_acc[1]) / traj_step_time, + (current_acc[2] - old_acc[2]) / traj_step_time,}; + + //jerk check + double jerk = sqrt(pow(current_jerk[0], 2) + pow(current_jerk[1], 2) + pow(current_jerk[2], 2)); + int sign = 0; + if (fabs(jerk) > MAX_JERK) { + ROS_WARN_THROTTLE(1.0, "Jerk exceeds the limit."); + for (int i = 0; i <3; i++) { + if (fabs(current_jerk[i]) > MAX_JERK) { + sign = (current_jerk[i] > 0) ? 1 : -1; + current_acc[i] = old_acc[i] + sign * MAX_JERK * traj_step_time; + current_vel[i] = old_vel[i] + current_acc[i] * traj_step_time; + } + } + } + + // acceleration check + double acc = sqrt(pow(current_acc[0], 2) + pow(current_acc[1], 2) + pow(current_acc[2], 2)); + if(fabs(acc) > MAX_ACC) { + ROS_WARN_THROTTLE(1.0, "Acceleration exceeds the limit."); + for(int i = 0; i < 3; i++) { + if (fabs(current_acc[i]) > MAX_ACC) { + sign = (current_acc[i] > 0) ? 1 : -1; + current_vel[i] = old_vel[i] + sign * MAX_ACC * traj_step_time; + } + } + } + + // velocity check + double vel = sqrt(pow(current_vel[0], 2) + pow(current_vel[1], 2) + pow(current_vel[2], 2)); + if(vel > MAX_VEL) { + ROS_WARN_THROTTLE(1.0, "Velocity exceeds the limit."); + for(int i = 0; i < 3; i++) { + if(fabs(current_vel[i]) > MAX_VEL) { + double sign = (current_vel[i] > 0) ? 1 : -1; + if(i == 0) + { + new_pose.position.x = current_pose_tcp[12] + sign * MAX_VEL * traj_step_time; + } + else if (i == 1) + { + new_pose.position.y = current_pose_tcp[13] + sign * MAX_VEL * traj_step_time; + } + else // i == 2 + { + new_pose.position.z = current_pose_tcp[14] + sign * MAX_VEL * traj_step_time; + } + } + } + } + else { + // update new pose with (limited) velocity + new_pose.position.x = current_pose_tcp[12] + current_vel[0] * traj_step_time; + new_pose.position.y = current_pose_tcp[13] + current_vel[1] * traj_step_time; + new_pose.position.z = current_pose_tcp[14] + current_vel[2] * traj_step_time; + } + + double dx = (new_pose.position.x - current_pose_tcp[12]) * update_step_size; + double dy = (new_pose.position.y - current_pose_tcp[13]) * update_step_size; + double dz = (new_pose.position.z - current_pose_tcp[14]) * update_step_size; + std::cout << "dx = " << dx << ", dy = " << dy << ", dz = " << dz << std::endl; + + // set new pose + current_pose_tcp[12] += dx; + current_pose_tcp[13] += dy; + current_pose_tcp[14] += dz; + // print current_pose_ + // ROS_INFO("current_pose_ = [%f, %f, %f]", current_pose_[12], current_pose_[13], current_pose_[14]); + cartesian_pose_handle_->setCommand(current_pose_tcp); + + // update old values + old_vel = current_vel; + old_acc = current_acc; + + COUNT += 1; + std::cout << "COUNT = " << COUNT << std::endl; + } + else { + ROS_WARN_THROTTLE(1.0, "No PoseArray msg received."); + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + cartesian_pose_handle_->setCommand(current_pose_tcp); + } +} + +// calculate the distances between the pose and all poses in a posearray +std::vector<double> CartesianTrajController::calc_distances(const geometry_msgs::PoseArray& pose_array, const std::vector<double>& tcp_pos) { + // array to save the distances + std::vector<double> distances; + for (int i = 0; i < pose_array.poses.size(); i++) { + double dx = pose_array.poses[i].position.x - tcp_pos.at(0); + double dy = pose_array.poses[i].position.y - tcp_pos.at(1); + double dz = pose_array.poses[i].position.z - tcp_pos.at(2); + double distance = sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2)); + distances.push_back(distance); + } + return distances; +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianTrajController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_controller.h b/fr3_impedance_controller_real/bak/cartesian_traj_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..0475b1120fdfbba89cef9efc18750909d5e5298e --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_controller.h @@ -0,0 +1,60 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> +#include <geometry_msgs/PoseArray.h> + +namespace franka_example_controllers { + +class CartesianTrajController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + franka_hw::FrankaPoseCartesianInterface* cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + double elapsed_time; + std::array<double, 16> initial_pose{}; + std::array<double, 16> current_pose_tcp{}; + + std::array<double, 3> old_vel{0.0, 0.0, 0.0}; + std::array<double, 3> old_acc{0.0, 0.0, 0.0}; + + const double traj_step_time = 0.2; + const double update_step_size = 0.001; + const double MAX_VEL = 1.7; //1.7 + const double MAX_ACC = 6; //13 + const double MAX_JERK = 1000.0; //6500 + + int COUNT = 0; + + ros::Subscriber traj_subscriber; + void trajCallback(const geometry_msgs::PoseArray::ConstPtr& msg); + geometry_msgs::PoseArray new_traj; + geometry_msgs::PoseArray traj_to_control; + geometry_msgs::Pose new_pose; + bool is_traj_received = false; + ros::Time last_msg_time; + double traj_start_time_; + int control_horizon = 7; + + std::vector<double> calc_distances(const geometry_msgs::PoseArray& pose_array, const std::vector<double>& tcp_pos); + +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_controller.launch b/fr3_impedance_controller_real/bak/cartesian_traj_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..599d25910274fd2f4c25189f7f3366b0803f306c --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_controller.launch @@ -0,0 +1,12 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <arg name="linear_gain" default="0.03" /> + <arg name="angular_gain" default="0.05" /> + <arg name="load_gripper" default="true" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_traj_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42eb2aefea304475988e74945cb23c232d699af3 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.cpp @@ -0,0 +1,226 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_traj_twist_correct_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> +#include <geometry_msgs/PoseArray.h> +#include <tf2_geometry_msgs/tf2_geometry_msgs.h> + + +namespace franka_example_controllers { + +bool CartesianTrajTwistCorrectController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) { + ROS_ERROR( + "CartesianPoseExampleController: Could not get Cartesian Pose " + "interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("CartesianPoseExampleController: Could not get parameter arm_id"); + return false; + } + + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianPoseExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("CartesianPoseExampleController: Could not get state interface from hardware"); + return false; + } + + // Initialize the pose array subscriber + traj_subscriber = node_handle.subscribe( + "/diffusion_policy_cartesian_pose_traj", 1, + &CartesianTrajTwistCorrectController::trajCallback, this); + + twist_subscriber = node_handle.subscribe("/spacenav/twist", 1, &CartesianTrajTwistCorrectController::twistCallback, this); + + return true; +} + +void CartesianTrajTwistCorrectController::starting(const ros::Time& /* time */) { + initial_pose = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "initial_pose = [" << initial_pose[12] << ", " << initial_pose[13] << ", " << initial_pose[14] << "]" << std::endl; +} + +//10Hz +void CartesianTrajTwistCorrectController::trajCallback(const geometry_msgs::PoseArray::ConstPtr& msg) { + new_traj = *msg; + is_traj_received = true; + last_msg_time = ros::Time::now(); +} + +// 30Hz +void CartesianTrajTwistCorrectController::twistCallback(const geometry_msgs::TwistConstPtr& msg) { + // std::cout << "twist by joystick: " << msg->linear.x << ", " << msg->linear.y << ", " << msg->linear.z << std::endl; // 0.4 ~ 0.6 + twist_command.linear.x = alpha * msg->linear.x; + twist_command.linear.y = alpha * msg->linear.y; + twist_command.linear.z = alpha * msg->linear.z; + twist_command.angular.x = 0; //angular_gain_ * msg->angular.x; + twist_command.angular.y = 0; //angular_gain_ * msg->angular.y; + twist_command.angular.z = 0; //angular_gain_ * msg->angular.z; +} + +//1000Hz +void CartesianTrajTwistCorrectController::update(const ros::Time& time , + const ros::Duration& period) { + if (is_traj_received && (ros::Time::now() - last_msg_time).toSec() > traj_step_time * 2) { + is_traj_received = false; + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + ROS_WARN_THROTTLE(1.0, "PoseArray msg stopped streaming."); + } + + if (is_traj_received) { + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + std::cout << "current_pose_tcp = [" << current_pose_tcp[12] << ", " << current_pose_tcp[13] << ", " << current_pose_tcp[14] << "]" << std::endl; + + // find the index of the closest pose in the trajectory and add a offset to it + std::vector<double> current_tcp_pos_vec; + current_tcp_pos_vec.assign(current_pose_tcp.begin()+12, current_pose_tcp.begin()+15); + std::vector<double> distances = calc_distances(new_traj, current_tcp_pos_vec); + auto min_value = std::min_element(distances.begin(), distances.end()); + int min_index = std::distance(distances.begin(), min_value); + std::cout << "min_index = " << min_index << std::endl; + int control_index = std::min(min_index+control_horizon, static_cast<int>(new_traj.poses.size())-1); + std::cout << "control_index = " << control_index << std::endl; + new_pose = new_traj.poses[control_index]; + std::cout << "new_pose = [" << new_pose.position.x << ", " << new_pose.position.y << ", " << new_pose.position.z << "]" << std::endl; + + //add the twist correction from twist command to the new_pose + // std::cout << "twist_command = [" << twist_command.linear.x << ", " << twist_command.linear.y << ", " << twist_command.linear.z << "]" << std::endl; + + new_pose.position.x += twist_command.linear.x; + new_pose.position.y += twist_command.linear.y; + new_pose.position.z += twist_command.linear.z; + + // calculate current velocity, acceleration and jerk + std::array<double, 3> current_vel = {(new_pose.position.x - current_pose_tcp[12]) / traj_step_time, + (new_pose.position.y - current_pose_tcp[13]) / traj_step_time, + (new_pose.position.z - current_pose_tcp[14]) / traj_step_time,}; + std::array<double, 3> current_acc = {(current_vel[0] - old_vel[0]) / traj_step_time, + (current_vel[1] - old_vel[1]) / traj_step_time, + (current_vel[2] - old_vel[2]) / traj_step_time,}; + std::array<double, 3> current_jerk = {(current_acc[0] - old_acc[0]) / traj_step_time, + (current_acc[1] - old_acc[1]) / traj_step_time, + (current_acc[2] - old_acc[2]) / traj_step_time,}; + + //jerk check + double jerk = sqrt(pow(current_jerk[0], 2) + pow(current_jerk[1], 2) + pow(current_jerk[2], 2)); + int sign = 0; + if (fabs(jerk) > MAX_JERK) { + ROS_WARN_THROTTLE(1.0, "Jerk exceeds the limit."); + for (int i = 0; i <3; i++) { + if (fabs(current_jerk[i]) > MAX_JERK) { + sign = (current_jerk[i] > 0) ? 1 : -1; + current_acc[i] = old_acc[i] + sign * MAX_JERK * traj_step_time; + current_vel[i] = old_vel[i] + current_acc[i] * traj_step_time; + } + } + } + + // acceleration check + double acc = sqrt(pow(current_acc[0], 2) + pow(current_acc[1], 2) + pow(current_acc[2], 2)); + if(fabs(acc) > MAX_ACC) { + ROS_WARN_THROTTLE(1.0, "Acceleration exceeds the limit."); + for(int i = 0; i < 3; i++) { + if (fabs(current_acc[i]) > MAX_ACC) { + sign = (current_acc[i] > 0) ? 1 : -1; + current_vel[i] = old_vel[i] + sign * MAX_ACC * traj_step_time; + } + } + } + + // velocity check + double vel = sqrt(pow(current_vel[0], 2) + pow(current_vel[1], 2) + pow(current_vel[2], 2)); + if(vel > MAX_VEL) { + ROS_WARN_THROTTLE(1.0, "Velocity exceeds the limit."); + for(int i = 0; i < 3; i++) { + if(fabs(current_vel[i]) > MAX_VEL) { + double sign = (current_vel[i] > 0) ? 1 : -1; + if(i == 0) + { + new_pose.position.x = current_pose_tcp[12] + sign * MAX_VEL * traj_step_time; + } + else if (i == 1) + { + new_pose.position.y = current_pose_tcp[13] + sign * MAX_VEL * traj_step_time; + } + else // i == 2 + { + new_pose.position.z = current_pose_tcp[14] + sign * MAX_VEL * traj_step_time; + } + } + } + } + else { + // update new pose with (limited) velocity + new_pose.position.x = current_pose_tcp[12] + current_vel[0] * traj_step_time; + new_pose.position.y = current_pose_tcp[13] + current_vel[1] * traj_step_time; + new_pose.position.z = current_pose_tcp[14] + current_vel[2] * traj_step_time; + } + + double dx = (new_pose.position.x - current_pose_tcp[12]) * update_step_size; + double dy = (new_pose.position.y - current_pose_tcp[13]) * update_step_size; + double dz = (new_pose.position.z - current_pose_tcp[14]) * update_step_size; + + // set new pose + current_pose_tcp[12] += dx; + current_pose_tcp[13] += dy; + current_pose_tcp[14] += dz; + // print current_pose_ + // ROS_INFO("current_pose_ = [%f, %f, %f]", current_pose_[12], current_pose_[13], current_pose_[14]); + cartesian_pose_handle_->setCommand(current_pose_tcp); + + // update old values + old_vel = current_vel; + old_acc = current_acc; + + COUNT += 1; + std::cout << "COUNT = " << COUNT << std::endl; + } + else { + ROS_WARN_THROTTLE(1.0, "No PoseArray msg received."); + current_pose_tcp = cartesian_pose_handle_->getRobotState().O_T_EE_d; + cartesian_pose_handle_->setCommand(current_pose_tcp); + } +} + +// calculate the distances between the pose and all poses in a posearray +std::vector<double> CartesianTrajTwistCorrectController::calc_distances(const geometry_msgs::PoseArray& pose_array, const std::vector<double>& tcp_pos) { + // array to save the distances + std::vector<double> distances; + for (int i = 0; i < pose_array.poses.size(); i++) { + double dx = pose_array.poses[i].position.x - tcp_pos.at(0); + double dy = pose_array.poses[i].position.y - tcp_pos.at(1); + double dz = pose_array.poses[i].position.z - tcp_pos.at(2); + double distance = sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2)); + distances.push_back(distance); + } + return distances; +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianTrajTwistCorrectController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.h b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..da612d9b7a8400ab644e301c3fc581820989cf01 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.h @@ -0,0 +1,68 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> +#include <geometry_msgs/PoseArray.h> +#include <geometry_msgs/Twist.h> +#include <sensor_msgs/Joy.h> + +namespace franka_example_controllers { + +class CartesianTrajTwistCorrectController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + + private: + franka_hw::FrankaPoseCartesianInterface* cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + double elapsed_time; + std::array<double, 16> initial_pose{}; + std::array<double, 16> current_pose_tcp{}; + + std::array<double, 3> old_vel{0.0, 0.0, 0.0}; + std::array<double, 3> old_acc{0.0, 0.0, 0.0}; + + const double alpha = 0.03; // gain for trajectory correction + + const double traj_step_time = 0.2; + const double update_step_size = 0.001; + const double MAX_VEL = 1.7; //1.7 + const double MAX_ACC = 6; //13 + const double MAX_JERK = 1000.0; //6500 + + int COUNT = 0; + + ros::Subscriber traj_subscriber; + ros::Subscriber twist_subscriber; + void trajCallback(const geometry_msgs::PoseArray::ConstPtr& msg); + void twistCallback(const geometry_msgs::TwistConstPtr& msg); + + geometry_msgs::PoseArray new_traj; + geometry_msgs::Pose new_pose; + geometry_msgs::Twist twist_command; + bool is_traj_received = false; + ros::Time last_msg_time; + double traj_start_time_; + int control_horizon = 7; + + std::vector<double> calc_distances(const geometry_msgs::PoseArray& pose_array, const std::vector<double>& tcp_pos); + +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.launch b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..55668126b1f9bee2253dec25a426ca06b6ae57e0 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_traj_twist_correct_controller.launch @@ -0,0 +1,13 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <arg name="linear_gain" default="0.03" /> + <arg name="angular_gain" default="0.05" /> + <arg name="load_gripper" default="true" /> + <include file="$(find spacenav_node)/launch/classic.launch" pass_all_args="true"/> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_traj_twist_correct_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.cpp b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67c34a255b04180b5cb4cfb5d48c003b4637705e --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.cpp @@ -0,0 +1,101 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_velocity_example_controller.h> + +#include <array> +#include <cmath> +#include <memory> +#include <string> + +#include <controller_interface/controller_base.h> +#include <hardware_interface/hardware_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool CartesianVelocityExampleController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("CartesianVelocityExampleController: Could not get parameter arm_id"); + return false; + } + + velocity_cartesian_interface_ = + robot_hardware->get<franka_hw::FrankaVelocityCartesianInterface>(); + if (velocity_cartesian_interface_ == nullptr) { + ROS_ERROR( + "CartesianVelocityExampleController: Could not get Cartesian velocity interface from " + "hardware"); + return false; + } + try { + velocity_cartesian_handle_ = std::make_unique<franka_hw::FrankaCartesianVelocityHandle>( + velocity_cartesian_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianVelocityExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("CartesianVelocityExampleController: Could not get state interface from hardware"); + return false; + } + + try { + auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + std::array<double, 7> q_start = {{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "CartesianVelocityExampleController: Robot is not in the expected starting position " + "for running this example. Run `roslaunch franka_example_controllers " + "move_to_start.launch robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` " + "first."); + return false; + } + } + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianVelocityExampleController: Exception getting state handle: " << e.what()); + return false; + } + + return true; +} + +void CartesianVelocityExampleController::starting(const ros::Time& /* time */) { + elapsed_time_ = ros::Duration(0.0); +} + +void CartesianVelocityExampleController::update(const ros::Time& /* time */, + const ros::Duration& period) { + elapsed_time_ += period; + + double time_max = 4.0; + double v_max = 0.05; + double angle = M_PI / 4.0; + double cycle = std::floor( + pow(-1.0, (elapsed_time_.toSec() - std::fmod(elapsed_time_.toSec(), time_max)) / time_max)); + double v = cycle * v_max / 2.0 * (1.0 - std::cos(2.0 * M_PI / time_max * elapsed_time_.toSec())); + double v_x = std::cos(angle) * v; + double v_z = -std::sin(angle) * v; + std::array<double, 6> command = {{v_x, 0.0, v_z, 0.0, 0.0, 0.0}}; + velocity_cartesian_handle_->setCommand(command); +} + +void CartesianVelocityExampleController::stopping(const ros::Time& /*time*/) { + // WARNING: DO NOT SEND ZERO VELOCITIES HERE AS IN CASE OF ABORTING DURING MOTION + // A JUMP TO ZERO WILL BE COMMANDED PUTTING HIGH LOADS ON THE ROBOT. LET THE DEFAULT + // BUILT-IN STOPPING BEHAVIOR SLOW DOWN THE ROBOT. +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianVelocityExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.h b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..95d4ace9a9e438d98e684fc1716b86487e793b17 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.h @@ -0,0 +1,32 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +namespace franka_example_controllers { + +class CartesianVelocityExampleController : public controller_interface::MultiInterfaceController< + franka_hw::FrankaVelocityCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void update(const ros::Time&, const ros::Duration& period) override; + void starting(const ros::Time&) override; + void stopping(const ros::Time&) override; + + private: + franka_hw::FrankaVelocityCartesianInterface* velocity_cartesian_interface_; + std::unique_ptr<franka_hw::FrankaCartesianVelocityHandle> velocity_cartesian_handle_; + ros::Duration elapsed_time_; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.launch b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..0eb440525daaa418f494eb36197b6e58c01cae43 --- /dev/null +++ b/fr3_impedance_controller_real/bak/cartesian_velocity_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_velocity_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/cfg/compliance_param.cfg b/fr3_impedance_controller_real/bak/compliance_param.cfg similarity index 100% rename from fr3_impedance_controller_real/cfg/compliance_param.cfg rename to fr3_impedance_controller_real/bak/compliance_param.cfg diff --git a/fr3_impedance_controller_real/bak/desired_mass_param.cfg b/fr3_impedance_controller_real/bak/desired_mass_param.cfg new file mode 100755 index 0000000000000000000000000000000000000000..2fb2f0a73713aca800ce8d9c64479dc5b7288e6d --- /dev/null +++ b/fr3_impedance_controller_real/bak/desired_mass_param.cfg @@ -0,0 +1,12 @@ +#!/usr/bin/env python +PACKAGE = "franka_example_controllers" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +gen.add("desired_mass", double_t, 0, "desired mass for rendered force due to gravity applied in the z axis", 0.0, 0.0, 2.0) +gen.add("k_p", double_t, 0, "force P gain", 0.0, 0.0, 2.0) +gen.add("k_i", double_t, 0, "force I gain", 0.0, 0.0, 2.0) + +exit(gen.generate(PACKAGE, "dynamic_mass", "desired_mass_param")) diff --git a/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.cpp b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fe0af19b539d7daab825629957af888dab44fe0 --- /dev/null +++ b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.cpp @@ -0,0 +1,412 @@ +// Copyright (c) 2019 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/dual_arm_cartesian_impedance_example_controller.h> + +#include <cmath> +#include <functional> +#include <memory> + +#include <controller_interface/controller_base.h> +#include <eigen_conversions/eigen_msg.h> +#include <franka/robot_state.h> +#include <franka_example_controllers/pseudo_inversion.h> +#include <franka_hw/trigger_rate.h> +#include <geometry_msgs/PoseStamped.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> +#include <ros/transport_hints.h> +#include <tf/transform_listener.h> +#include <tf_conversions/tf_eigen.h> + +namespace franka_example_controllers { + +bool DualArmCartesianImpedanceExampleController::initArm( + hardware_interface::RobotHW* robot_hw, + const std::string& arm_id, + const std::vector<std::string>& joint_names) { + FrankaDataContainer arm_data; + auto* model_interface = robot_hw->get<franka_hw::FrankaModelInterface>(); + if (model_interface == nullptr) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Error getting model interface from hardware"); + return false; + } + try { + arm_data.model_handle_ = std::make_unique<franka_hw::FrankaModelHandle>( + model_interface->getHandle(arm_id + "_model")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Exception getting model handle from " + "interface: " + << ex.what()); + return false; + } + + auto* state_interface = robot_hw->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Error getting state interface from hardware"); + return false; + } + try { + arm_data.state_handle_ = std::make_unique<franka_hw::FrankaStateHandle>( + state_interface->getHandle(arm_id + "_robot")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Exception getting state handle from " + "interface: " + << ex.what()); + return false; + } + + auto* effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); + if (effort_joint_interface == nullptr) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Error getting effort joint interface from " + "hardware"); + return false; + } + for (size_t i = 0; i < 7; ++i) { + try { + arm_data.joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i])); + } catch (const hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Exception getting joint handles: " + << ex.what()); + return false; + } + } + + arm_data.position_d_.setZero(); + arm_data.orientation_d_.coeffs() << 0.0, 0.0, 0.0, 1.0; + arm_data.position_d_target_.setZero(); + arm_data.orientation_d_target_.coeffs() << 0.0, 0.0, 0.0, 1.0; + + arm_data.cartesian_stiffness_.setZero(); + arm_data.cartesian_damping_.setZero(); + + arms_data_.emplace(std::make_pair(arm_id, std::move(arm_data))); + + return true; +} + +bool DualArmCartesianImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle) { + std::vector<double> cartesian_stiffness_vector; + std::vector<double> cartesian_damping_vector; + + if (!node_handle.getParam("left/arm_id", left_arm_id_)) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Could not read parameter left_arm_id_"); + return false; + } + std::vector<std::string> left_joint_names; + if (!node_handle.getParam("left/joint_names", left_joint_names) || left_joint_names.size() != 7) { + ROS_ERROR( + "DualArmCartesianImpedanceExampleController: Invalid or no left_joint_names parameters " + "provided, " + "aborting controller init!"); + return false; + } + + if (!node_handle.getParam("right/arm_id", right_arm_id_)) { + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Could not read parameter right_arm_id_"); + return false; + } + + boost::function<void(const geometry_msgs::PoseStamped::ConstPtr&)> callback = + boost::bind(&DualArmCartesianImpedanceExampleController::targetPoseCallback, this, _1); + + ros::SubscribeOptions subscribe_options; + subscribe_options.init("centering_frame_target_pose", 1, callback); + subscribe_options.transport_hints = ros::TransportHints().reliable().tcpNoDelay(); + sub_target_pose_left_ = node_handle.subscribe(subscribe_options); + + std::vector<std::string> right_joint_names; + if (!node_handle.getParam("right/joint_names", right_joint_names) || + right_joint_names.size() != 7) { + ROS_ERROR( + "DualArmCartesianImpedanceExampleController: Invalid or no right_joint_names parameters " + "provided, " + "aborting controller init!"); + return false; + } + + bool left_success = initArm(robot_hw, left_arm_id_, left_joint_names); + bool right_success = initArm(robot_hw, right_arm_id_, right_joint_names); + + dynamic_reconfigure_compliance_param_node_ = + ros::NodeHandle("dynamic_reconfigure_compliance_param_node"); + + dynamic_server_compliance_param_ = std::make_unique<dynamic_reconfigure::Server< + franka_combined_example_controllers::dual_arm_compliance_paramConfig>>( + dynamic_reconfigure_compliance_param_node_); + + dynamic_server_compliance_param_->setCallback(boost::bind( + &DualArmCartesianImpedanceExampleController::complianceParamCallback, this, _1, _2)); + + // Get the transformation from right_O_frame to left_O_frame + tf::StampedTransform transform; + tf::TransformListener listener; + try { + if (listener.waitForTransform(left_arm_id_ + "_link0", right_arm_id_ + "_link0", ros::Time(0), + ros::Duration(4.0))) { + listener.lookupTransform(left_arm_id_ + "_link0", right_arm_id_ + "_link0", ros::Time(0), + transform); + } else { + ROS_ERROR( + "DualArmCartesianImpedanceExampleController: Failed to read transform from %s to %s. " + "Aborting init!", + (right_arm_id_ + "_link0").c_str(), (left_arm_id_ + "_link0").c_str()); + return false; + } + } catch (tf::TransformException& ex) { + ROS_ERROR("DualArmCartesianImpedanceExampleController: %s", ex.what()); + return false; + } + tf::transformTFToEigen(transform, Ol_T_Or_); // NOLINT (readability-identifier-naming) + + // Setup publisher for the centering frame. + publish_rate_ = franka_hw::TriggerRate(30.0); + center_frame_pub_.init(node_handle, "centering_frame", 1, true); + + return left_success && right_success; +} + +void DualArmCartesianImpedanceExampleController::startingArm(FrankaDataContainer& arm_data) { + // compute initial velocity with jacobian and set x_attractor and q_d_nullspace + // to initial configuration + franka::RobotState initial_state = arm_data.state_handle_->getRobotState(); + // get jacobian + std::array<double, 42> jacobian_array = + arm_data.model_handle_->getZeroJacobian(franka::Frame::kEndEffector); + // convert to eigen + Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> dq_initial(initial_state.dq.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> q_initial(initial_state.q.data()); + Eigen::Affine3d initial_transform(Eigen::Matrix4d::Map(initial_state.O_T_EE.data())); + + // set target point to current state + arm_data.position_d_ = initial_transform.translation(); + arm_data.orientation_d_ = Eigen::Quaterniond(initial_transform.rotation()); + arm_data.position_d_target_ = initial_transform.translation(); + arm_data.orientation_d_target_ = Eigen::Quaterniond(initial_transform.rotation()); + + // set nullspace target configuration to initial q + arm_data.q_d_nullspace_ = q_initial; +} + +void DualArmCartesianImpedanceExampleController::starting(const ros::Time& /*time*/) { + for (auto& arm_data : arms_data_) { + startingArm(arm_data.second); + } + franka::RobotState robot_state_right = + arms_data_.at(right_arm_id_).state_handle_->getRobotState(); + franka::RobotState robot_state_left = arms_data_.at(left_arm_id_).state_handle_->getRobotState(); + Eigen::Affine3d Ol_T_EEl(Eigen::Matrix4d::Map( // NOLINT (readability-identifier-naming) + robot_state_left.O_T_EE.data())); // NOLINT (readability-identifier-naming) + Eigen::Affine3d Or_T_EEr(Eigen::Matrix4d::Map( // NOLINT (readability-identifier-naming) + robot_state_right.O_T_EE.data())); // NOLINT (readability-identifier-naming) + EEr_T_EEl_ = + Or_T_EEr.inverse() * Ol_T_Or_.inverse() * Ol_T_EEl; // NOLINT (readability-identifier-naming) + EEl_T_C_.setIdentity(); + Eigen::Vector3d EEr_r_EEr_EEl = // NOLINT (readability-identifier-naming) + EEr_T_EEl_.translation(); // NOLINT (readability-identifier-naming) + EEl_T_C_.translation() = -0.5 * EEr_T_EEl_.inverse().rotation() * EEr_r_EEr_EEl; +} + +void DualArmCartesianImpedanceExampleController::update(const ros::Time& /*time*/, + const ros::Duration& /*period*/) { + for (auto& arm_data : arms_data_) { + updateArm(arm_data.second); // NOLINT + } + if (publish_rate_()) { + publishCenteringPose(); + } +} + +void DualArmCartesianImpedanceExampleController::updateArm(FrankaDataContainer& arm_data) { + // get state variables + franka::RobotState robot_state = arm_data.state_handle_->getRobotState(); + std::array<double, 49> inertia_array = arm_data.model_handle_->getMass(); + std::array<double, 7> coriolis_array = arm_data.model_handle_->getCoriolis(); + std::array<double, 42> jacobian_array = + arm_data.model_handle_->getZeroJacobian(franka::Frame::kEndEffector); + + // convert to Eigen + Eigen::Map<Eigen::Matrix<double, 7, 1>> coriolis(coriolis_array.data()); + Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> q(robot_state.q.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> dq(robot_state.dq.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_J_d( // NOLINT (readability-identifier-naming) + robot_state.tau_J_d.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 pose + // position error + Eigen::Matrix<double, 6, 1> error; + error.head(3) << position - arm_data.position_d_; + + // orientation error + if (arm_data.orientation_d_.coeffs().dot(orientation.coeffs()) < 0.0) { + orientation.coeffs() << -orientation.coeffs(); + } + // "difference" quaternion + Eigen::Quaterniond error_quaternion(orientation * arm_data.orientation_d_.inverse()); + // convert to axis angle + Eigen::AngleAxisd error_quaternion_angle_axis(error_quaternion); + // compute "orientation error" + error.tail(3) << error_quaternion_angle_axis.axis() * error_quaternion_angle_axis.angle(); + + // compute control + // allocate variables + Eigen::VectorXd tau_task(7), tau_nullspace(7), tau_d(7); + + // pseudoinverse for nullspace handling + // kinematic pseuoinverse + Eigen::MatrixXd jacobian_transpose_pinv; + franka_example_controllers::pseudoInverse(jacobian.transpose(), jacobian_transpose_pinv); + + // Cartesian PD control with damping ratio = 1 + tau_task << jacobian.transpose() * (-arm_data.cartesian_stiffness_ * error - + arm_data.cartesian_damping_ * (jacobian * dq)); + // nullspace PD control with damping ratio = 1 + tau_nullspace << (Eigen::MatrixXd::Identity(7, 7) - + jacobian.transpose() * jacobian_transpose_pinv) * + (arm_data.nullspace_stiffness_ * (arm_data.q_d_nullspace_ - q) - + (2.0 * sqrt(arm_data.nullspace_stiffness_)) * dq); + // Desired torque + tau_d << tau_task + tau_nullspace + coriolis; + // Saturate torque rate to avoid discontinuities + tau_d << saturateTorqueRate(arm_data, tau_d, tau_J_d); + for (size_t i = 0; i < 7; ++i) { + arm_data.joint_handles_[i].setCommand(tau_d(i)); + } + + // update parameters changed online either through dynamic reconfigure or through the interactive + // target by filtering + arm_data.cartesian_stiffness_ = arm_data.filter_params_ * arm_data.cartesian_stiffness_target_ + + (1.0 - arm_data.filter_params_) * arm_data.cartesian_stiffness_; + arm_data.cartesian_damping_ = arm_data.filter_params_ * arm_data.cartesian_damping_target_ + + (1.0 - arm_data.filter_params_) * arm_data.cartesian_damping_; + arm_data.nullspace_stiffness_ = arm_data.filter_params_ * arm_data.nullspace_stiffness_target_ + + (1.0 - arm_data.filter_params_) * arm_data.nullspace_stiffness_; + arm_data.position_d_ = arm_data.filter_params_ * arm_data.position_d_target_ + + (1.0 - arm_data.filter_params_) * arm_data.position_d_; + arm_data.orientation_d_ = + arm_data.orientation_d_.slerp(arm_data.filter_params_, arm_data.orientation_d_target_); +} + +Eigen::Matrix<double, 7, 1> DualArmCartesianImpedanceExampleController::saturateTorqueRate( + const FrankaDataContainer& arm_data, + const Eigen::Matrix<double, 7, 1>& tau_d_calculated, + const Eigen::Matrix<double, 7, 1>& tau_J_d) { // NOLINT (readability-identifier-naming) + Eigen::Matrix<double, 7, 1> tau_d_saturated{}; + for (size_t i = 0; i < 7; i++) { + double difference = tau_d_calculated[i] - tau_J_d[i]; + tau_d_saturated[i] = tau_J_d[i] + std::max(std::min(difference, arm_data.delta_tau_max_), + -arm_data.delta_tau_max_); + } + return tau_d_saturated; +} + +void DualArmCartesianImpedanceExampleController::complianceParamCallback( + franka_combined_example_controllers::dual_arm_compliance_paramConfig& config, + uint32_t /*level*/) { + auto& left_arm_data = arms_data_.at(left_arm_id_); + left_arm_data.cartesian_stiffness_target_.setIdentity(); + left_arm_data.cartesian_stiffness_target_.topLeftCorner(3, 3) + << config.left_translational_stiffness * Eigen::Matrix3d::Identity(); + left_arm_data.cartesian_stiffness_target_.bottomRightCorner(3, 3) + << config.left_rotational_stiffness * Eigen::Matrix3d::Identity(); + left_arm_data.cartesian_damping_target_.setIdentity(); + + left_arm_data.cartesian_damping_target_.topLeftCorner(3, 3) + << 2 * sqrt(config.left_translational_stiffness) * Eigen::Matrix3d::Identity(); + left_arm_data.cartesian_damping_target_.bottomRightCorner(3, 3) + << 2 * sqrt(config.left_rotational_stiffness) * Eigen::Matrix3d::Identity(); + left_arm_data.nullspace_stiffness_target_ = config.left_nullspace_stiffness; + + auto& right_arm_data = arms_data_.at(right_arm_id_); + right_arm_data.cartesian_stiffness_target_.setIdentity(); + right_arm_data.cartesian_stiffness_target_.topLeftCorner(3, 3) + << config.right_translational_stiffness * Eigen::Matrix3d::Identity(); + right_arm_data.cartesian_stiffness_target_.bottomRightCorner(3, 3) + << config.right_rotational_stiffness * Eigen::Matrix3d::Identity(); + right_arm_data.cartesian_damping_target_.setIdentity(); + + right_arm_data.cartesian_damping_target_.topLeftCorner(3, 3) + << 2 * sqrt(config.right_translational_stiffness) * Eigen::Matrix3d::Identity(); + right_arm_data.cartesian_damping_target_.bottomRightCorner(3, 3) + << 2 * sqrt(config.right_rotational_stiffness) * Eigen::Matrix3d::Identity(); + right_arm_data.nullspace_stiffness_target_ = config.right_nullspace_stiffness; +} + +void DualArmCartesianImpedanceExampleController::targetPoseCallback( + const geometry_msgs::PoseStamped::ConstPtr& msg) { + try { + if (msg->header.frame_id != left_arm_id_ + "_link0") { // NOLINT + ROS_ERROR_STREAM( + "DualArmCartesianImpedanceExampleController: Got pose target with invalid" + " frame_id " + << msg->header.frame_id << ". Expected " << left_arm_id_ + "_link0"); + return; + } + + // Set target for the left robot. + auto& left_arm_data = arms_data_.at(left_arm_id_); + Eigen::Affine3d Ol_T_C{}; // NOLINT (readability-identifier-naming) + tf::poseMsgToEigen(msg->pose, Ol_T_C); + Eigen::Affine3d Ol_T_EEl_d = // NOLINT (readability-identifier-naming) + Ol_T_C * EEl_T_C_.inverse(); // NOLINT (readability-identifier-naming) + left_arm_data.position_d_target_ = Ol_T_EEl_d.translation(); + Eigen::Quaterniond last_orientation_d_target(left_arm_data.orientation_d_target_); + Eigen::Quaterniond new_orientation_target(Ol_T_EEl_d.rotation()); + if (last_orientation_d_target.coeffs().dot(new_orientation_target.coeffs()) < 0.0) { + new_orientation_target.coeffs() << -new_orientation_target.coeffs(); + } + Ol_T_EEl_d.linear() = new_orientation_target.matrix(); + left_arm_data.orientation_d_target_ = Ol_T_EEl_d.rotation(); + + // Compute target for the right endeffector given the static desired transform from left to + // right endeffector. + Eigen::Affine3d Or_T_EEr_d = Ol_T_Or_.inverse() // NOLINT (readability-identifier-naming) + * Ol_T_EEl_d * // NOLINT (readability-identifier-naming) + EEr_T_EEl_.inverse(); // NOLINT (readability-identifier-naming) + auto& right_arm_data = arms_data_.at(right_arm_id_); + right_arm_data.position_d_target_ = + Or_T_EEr_d.translation(); // NOLINT (readability-identifier-naming) + last_orientation_d_target = Eigen::Quaterniond(right_arm_data.orientation_d_target_); + right_arm_data.orientation_d_target_ = + Or_T_EEr_d.rotation(); // NOLINT (readability-identifier-naming) + if (last_orientation_d_target.coeffs().dot(right_arm_data.orientation_d_target_.coeffs()) < + 0.0) { + right_arm_data.orientation_d_target_.coeffs() + << -right_arm_data.orientation_d_target_.coeffs(); + } + + } catch (std::out_of_range& ex) { + ROS_ERROR_STREAM("DualArmCartesianImpedanceExampleController: Exception setting target poses."); + } +} + +void DualArmCartesianImpedanceExampleController::publishCenteringPose() { + if (center_frame_pub_.trylock()) { + franka::RobotState robot_state_left = + arms_data_.at(left_arm_id_).state_handle_->getRobotState(); + Eigen::Affine3d Ol_T_EEl(Eigen::Matrix4d::Map( // NOLINT (readability-identifier-naming) + robot_state_left.O_T_EE.data())); // NOLINT (readability-identifier-naming) + Eigen::Affine3d Ol_T_C = Ol_T_EEl * EEl_T_C_; // NOLINT (readability-identifier-naming) + tf::poseEigenToMsg(Ol_T_C, center_frame_pub_.msg_.pose); + center_frame_pub_.msg_.header.frame_id = left_arm_id_ + "_link0"; + center_frame_pub_.unlockAndPublish(); + } +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::DualArmCartesianImpedanceExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.h b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..4247a47aa09c88690446d508662d8c8bf1da9677 --- /dev/null +++ b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.h @@ -0,0 +1,182 @@ +// Copyright (c) 2019 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> +#include <vector> + +#include <controller_interface/multi_interface_controller.h> +#include <dynamic_reconfigure/server.h> +#include <geometry_msgs/PoseStamped.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <realtime_tools/realtime_publisher.h> +#include <ros/node_handle.h> +#include <ros/time.h> +#include <Eigen/Dense> + +#include <franka_example_controllers/dual_arm_compliance_paramConfig.h> +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/franka_state_interface.h> +#include <franka_hw/trigger_rate.h> + +namespace franka_example_controllers { + +/** + * This container holds all data and parameters used to control one panda arm with a Cartesian + * impedance control law tracking a desired target pose. + */ +struct FrankaDataContainer { + std::unique_ptr<franka_hw::FrankaStateHandle> + state_handle_; ///< To read to complete robot state. + std::unique_ptr<franka_hw::FrankaModelHandle> + model_handle_; ///< To have access to e.g. jacobians. + std::vector<hardware_interface::JointHandle> joint_handles_; ///< To command joint torques. + double filter_params_{0.005}; ///< [-] PT1-Filter constant to smooth target values set + ///< by dynamic reconfigure servers (stiffness/damping) + ///< or interactive markers for the target poses. + double nullspace_stiffness_{20.0}; ///< [Nm/rad] To track the initial joint configuration in + ///< the nullspace of the Cartesian motion. + double nullspace_stiffness_target_{20.0}; ///< [Nm/rad] Unfiltered raw value. + const double delta_tau_max_{1.0}; ///< [Nm/ms] Maximum difference in joint-torque per + ///< timestep. Used to saturated torque rates to ensure + ///< feasible commands. + Eigen::Matrix<double, 6, 6> cartesian_stiffness_; ///< To track the target pose. + Eigen::Matrix<double, 6, 6> cartesian_stiffness_target_; ///< Unfiltered raw value. + Eigen::Matrix<double, 6, 6> cartesian_damping_; ///< To damp cartesian motions. + Eigen::Matrix<double, 6, 6> cartesian_damping_target_; ///< Unfiltered raw value. + Eigen::Matrix<double, 7, 1> q_d_nullspace_; ///< Target joint pose for nullspace + ///< motion. For now we track the + ///< initial joint pose. + Eigen::Vector3d position_d_; ///< Target position of the end effector. + Eigen::Quaterniond orientation_d_; ///< Target orientation of the end effector. + Eigen::Vector3d position_d_target_; ///< Unfiltered raw value. + Eigen::Quaterniond orientation_d_target_; ///< Unfiltered raw value. +}; + +/** + * Controller class for ros_control that renders two decoupled Cartesian impedances for the + * tracking of two target poses for the two endeffectors. The controller can be reparameterized at + * runtime via dynamic reconfigure servers. + */ +class DualArmCartesianImpedanceExampleController + : public controller_interface::MultiInterfaceController< + franka_hw::FrankaModelInterface, + hardware_interface::EffortJointInterface, + franka_hw::FrankaStateInterface> { + public: + /** + * Initializes the controller class to be ready to run. + * + * @param[in] robot_hw Pointer to a RobotHW class to get interfaces and resource handles. + * @param[in] node_handle Nodehandle that allows getting parameterizations from the server and + * starting subscribers. + * @return True if the controller was initialized successfully, false otherwise. + */ + bool init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) override; + + /** + * Prepares the controller for the real-time execution. This method is executed once every time + * the controller is started and runs in real-time. + */ + void starting(const ros::Time&) override; + + /** + * Computes the control-law and commands the resulting joint torques to the robot. + * + * @param[in] period The control period (here 0.001s). + */ + void update(const ros::Time&, const ros::Duration& period) override; + + private: + std::map<std::string, FrankaDataContainer> + arms_data_; ///< Holds all relevant data for both arms. + std::string left_arm_id_; ///< Name of the left arm, retrieved from the parameter server. + std::string right_arm_id_; ///< Name of the right arm, retrieved from the parameter server. + + ///< Transformation between base frames of the robots. + Eigen::Affine3d Ol_T_Or_; // NOLINT (readability-identifier-naming) + ///< Target transformation between the two endeffectors. + Eigen::Affine3d EEr_T_EEl_; // NOLINT (readability-identifier-naming) + ///< Transformation from the centering frame to the left end effector. + Eigen::Affine3d EEl_T_C_{}; + + ///< Publisher for the centering tracking frame of the coordinated motion. + realtime_tools::RealtimePublisher<geometry_msgs::PoseStamped> center_frame_pub_; + ///< Rate to trigger publishing the current pose of the centering frame. + franka_hw::TriggerRate publish_rate_; + + /** + * Saturates torque commands to ensure feasibility. + * + * @param[in] arm_data The data container of the arm. + * @param[in] tau_d_calculated The raw command according to the control law. + * @param[in] tau_J_d The current desired torque, read from the robot state. + * @return The saturated torque command for the 7 joints of one arm. + */ + 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); // NOLINT (readability-identifier-naming) + + /** + * Initializes a single Panda robot arm. + * + * @param[in] robot_hw A pointer the RobotHW class for getting interfaces and resource handles. + * @param[in] arm_id The name of the panda arm. + * @param[in] joint_names The names of all joints of the panda. + * @return True if successful, false otherwise. + */ + bool initArm(hardware_interface::RobotHW* robot_hw, + const std::string& arm_id, + const std::vector<std::string>& joint_names); + + /** + * Computes the decoupled controller update for a single arm. + * + * @param[in] arm_data The data container of the arm to control. + */ + void updateArm(FrankaDataContainer& arm_data); + + /** + * Prepares all internal states to be ready to run the real-time control for one arm. + * + * @param[in] arm_data The data container of the arm to prepare for the control loop. + */ + void startingArm(FrankaDataContainer& arm_data); + + ///< Dynamic reconfigure server + std::unique_ptr<dynamic_reconfigure::Server< + franka_combined_example_controllers::dual_arm_compliance_paramConfig>> + dynamic_server_compliance_param_; + + ///< Nodehandle for the dynamic reconfigure namespace + ros::NodeHandle dynamic_reconfigure_compliance_param_node_; + + /** + * Callback for updates on the parameterization of the controller in terms of stiffnesses. + * + * @param[in] config Data container for configuration updates. + */ + void complianceParamCallback( + franka_combined_example_controllers::dual_arm_compliance_paramConfig& config, + uint32_t /*level*/); + + ///< Target pose subscriber + ros::Subscriber sub_target_pose_left_; + + /** + * Callback method that handles updates of the target poses. + * + * @param[in] msg New target pose. + */ + void targetPoseCallback(const geometry_msgs::PoseStamped::ConstPtr& msg); + + /** + * Publishes a Pose Stamped for visualization of the current centering pose. + */ + void publishCenteringPose(); +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.launch b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..8320e60106a220904ec223138455f649a16ace2b --- /dev/null +++ b/fr3_impedance_controller_real/bak/dual_arm_cartesian_impedance_example_controller.launch @@ -0,0 +1,23 @@ +<?xml version="1.0" ?> +<launch> + <!--Be sure to pass the IPs of your pandas like robot_ips:="{panda_1/robot_ip: <my_ip_1>, panda_2/robot_ip: <my_ip_2>}" --> + <arg name="robot_ips" /> + + <arg name="robot_id" default="panda_dual" /> + <arg name="rviz" default="true" /> + <arg name="rqt" default="true" /> + + <include file="$(find franka_control)/launch/franka_combined_control.launch" > + <arg name="robot_id" value="$(arg robot_id)" /> + <arg name="robot_ips" value="$(arg robot_ips)" /> + </include> + + <group ns="$(arg robot_id)"> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="dual_arm_cartesian_impedance_example_controller"/> + <node name="interactive_marker_left" pkg="franka_example_controllers" type="dual_arm_interactive_marker.py" + args="--right_arm_id panda_1 --left_arm_id panda_2" required="false" output="screen" /> + <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" required="false" if="$(arg rqt)"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/franka_dual_description_with_marker.rviz" if="$(arg rviz)"/> + </group> +</launch> diff --git a/fr3_impedance_controller_real/bak/dual_arm_compliance_param.cfg b/fr3_impedance_controller_real/bak/dual_arm_compliance_param.cfg new file mode 100755 index 0000000000000000000000000000000000000000..ef80c4138f5093d77a42ab4b2a45070ff045545d --- /dev/null +++ b/fr3_impedance_controller_real/bak/dual_arm_compliance_param.cfg @@ -0,0 +1,16 @@ +#!/usr/bin/env python +PACKAGE = "franka_combined_example_controllers" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +gen.add("left_translational_stiffness", double_t, 0, "Cartesian translational stiffness", 200, 0, 400) +gen.add("left_rotational_stiffness", double_t, 0, "Cartesian rotational stiffness", 10, 0, 30) +gen.add("left_nullspace_stiffness", double_t, 0, "Stiffness of the joint space nullspace controller (the desired configuration is the one at startup)", 0, 0, 100) + +gen.add("right_translational_stiffness", double_t, 0, "Cartesian translational stiffness", 200, 0, 400) +gen.add("right_rotational_stiffness", double_t, 0, "Cartesian rotational stiffness", 10, 0, 30) +gen.add("right_nullspace_stiffness", double_t, 0, "Stiffness of the joint space nullspace controller (the desired configuration is the one at startup)", 0, 0, 100) + +exit(gen.generate(PACKAGE, "dynamic_compliance", "dual_arm_compliance_param")) diff --git a/fr3_impedance_controller_real/bak/elbow_example_controller.cpp b/fr3_impedance_controller_real/bak/elbow_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c988cb502164eb85ef0a803f9347b58a28ab625a --- /dev/null +++ b/fr3_impedance_controller_real/bak/elbow_example_controller.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/elbow_example_controller.h> + +#include <cmath> +#include <memory> +#include <stdexcept> +#include <string> + +#include <controller_interface/controller_base.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool ElbowExampleController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + cartesian_pose_interface_ = robot_hardware->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface_ == nullptr) { + ROS_ERROR("ElbowExampleController: Could not get Cartesian Pose interface from hardware"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("ElbowExampleController: Could not get parameter arm_id"); + return false; + } + + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM("ElbowExampleController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("ElbowExampleController: Could not get state interface from hardware"); + return false; + } + + try { + auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + std::array<double, 7> q_start{{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "ElbowExampleController: Robot is not in the expected starting position for " + "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " + "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); + return false; + } + } + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM("ElbowExampleController: Exception getting state handle: " << e.what()); + return false; + } + + return true; +} + +void ElbowExampleController::starting(const ros::Time& /* time */) { + initial_pose_ = cartesian_pose_handle_->getRobotState().O_T_EE_d; + initial_elbow_ = cartesian_pose_handle_->getRobotState().elbow_d; + elapsed_time_ = ros::Duration(0.0); +} + +void ElbowExampleController::update(const ros::Time& /* time */, const ros::Duration& period) { + elapsed_time_ += period; + + double angle = M_PI / 10.0 * (1.0 - std::cos(M_PI / 5.0 * elapsed_time_.toSec())); + auto elbow = initial_elbow_; + elbow[0] += angle; + + cartesian_pose_handle_->setCommand(initial_pose_, elbow); +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::ElbowExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/elbow_example_controller.h b/fr3_impedance_controller_real/bak/elbow_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..70a8cfb16cfa85ba695fc1393c9daaad6156ec04 --- /dev/null +++ b/fr3_impedance_controller_real/bak/elbow_example_controller.h @@ -0,0 +1,35 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_cartesian_command_interface.h> + +namespace franka_example_controllers { + +class ElbowExampleController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaPoseCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + franka_hw::FrankaPoseCartesianInterface* cartesian_pose_interface_; + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + ros::Duration elapsed_time_; + std::array<double, 16> initial_pose_{}; + std::array<double, 2> initial_elbow_{}; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/elbow_example_controller.launch b/fr3_impedance_controller_real/bak/elbow_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..890f86545428747108774c36e87ef05984cb3008 --- /dev/null +++ b/fr3_impedance_controller_real/bak/elbow_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="elbow_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/force_example_controller.cpp b/fr3_impedance_controller_real/bak/force_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2923ad58cfaa9a5e41f37469e812d1838172d517 --- /dev/null +++ b/fr3_impedance_controller_real/bak/force_example_controller.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/force_example_controller.h> + +#include <cmath> +#include <memory> + +#include <controller_interface/controller_base.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +#include <franka/robot_state.h> + +namespace franka_example_controllers { + +bool ForceExampleController::init(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle) { + std::vector<std::string> joint_names; + std::string arm_id; + ROS_WARN( + "ForceExampleController: Make sure your robot's endeffector is in contact " + "with a horizontal surface before starting the controller!"); + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("ForceExampleController: Could not read parameter arm_id"); + return false; + } + if (!node_handle.getParam("joint_names", joint_names) || joint_names.size() != 7) { + ROS_ERROR( + "ForceExampleController: Invalid or no joint_names parameters provided, aborting " + "controller init!"); + return false; + } + + auto* model_interface = robot_hw->get<franka_hw::FrankaModelInterface>(); + if (model_interface == nullptr) { + ROS_ERROR_STREAM("ForceExampleController: Error getting model interface from hardware"); + return false; + } + try { + model_handle_ = std::make_unique<franka_hw::FrankaModelHandle>( + model_interface->getHandle(arm_id + "_model")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "ForceExampleController: Exception getting model handle from interface: " << ex.what()); + return false; + } + + auto* state_interface = robot_hw->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR_STREAM("ForceExampleController: Error getting state interface from hardware"); + return false; + } + try { + state_handle_ = std::make_unique<franka_hw::FrankaStateHandle>( + state_interface->getHandle(arm_id + "_robot")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "ForceExampleController: Exception getting state handle from interface: " << ex.what()); + return false; + } + + auto* effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); + if (effort_joint_interface == nullptr) { + ROS_ERROR_STREAM("ForceExampleController: Error getting effort joint interface from hardware"); + return false; + } + for (size_t i = 0; i < 7; ++i) { + try { + joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i])); + } catch (const hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM("ForceExampleController: Exception getting joint handles: " << ex.what()); + return false; + } + } + + dynamic_reconfigure_desired_mass_param_node_ = + ros::NodeHandle("dynamic_reconfigure_desired_mass_param_node"); + dynamic_server_desired_mass_param_ = std::make_unique< + dynamic_reconfigure::Server<franka_example_controllers::desired_mass_paramConfig>>( + + dynamic_reconfigure_desired_mass_param_node_); + dynamic_server_desired_mass_param_->setCallback( + boost::bind(&ForceExampleController::desiredMassParamCallback, this, _1, _2)); + + return true; +} + +void ForceExampleController::starting(const ros::Time& /*time*/) { + franka::RobotState robot_state = state_handle_->getRobotState(); + std::array<double, 7> gravity_array = model_handle_->getGravity(); + Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_measured(robot_state.tau_J.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> gravity(gravity_array.data()); + // Bias correction for the current external torque + tau_ext_initial_ = tau_measured - gravity; + tau_error_.setZero(); +} + +void ForceExampleController::update(const ros::Time& /*time*/, const ros::Duration& period) { + franka::RobotState robot_state = state_handle_->getRobotState(); + std::array<double, 42> jacobian_array = + model_handle_->getZeroJacobian(franka::Frame::kEndEffector); + std::array<double, 7> gravity_array = model_handle_->getGravity(); + Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_measured(robot_state.tau_J.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_J_d( // NOLINT (readability-identifier-naming) + robot_state.tau_J_d.data()); + Eigen::Map<Eigen::Matrix<double, 7, 1>> gravity(gravity_array.data()); + + Eigen::Matrix<double, 7, 1> tau_d, tau_cmd, tau_ext; + Eigen::Matrix<double, 6, 1> desired_force_torque; + desired_force_torque.setZero(); + desired_force_torque(2) = desired_mass_ * -9.81; + tau_ext = tau_measured - gravity - tau_ext_initial_; + tau_d = jacobian.transpose() * desired_force_torque; + tau_error_ = tau_error_ + period.toSec() * (tau_d - tau_ext); + // FF + PI control (PI gains are initially all 0) + tau_cmd = tau_d + k_p_ * (tau_d - tau_ext) + k_i_ * tau_error_; + tau_cmd = saturateTorqueRate(tau_cmd, tau_J_d); + + for (size_t i = 0; i < 7; ++i) { + joint_handles_[i].setCommand(tau_cmd(i)); + } + + // Update signals changed online through dynamic reconfigure + desired_mass_ = filter_gain_ * target_mass_ + (1 - filter_gain_) * desired_mass_; + k_p_ = filter_gain_ * target_k_p_ + (1 - filter_gain_) * k_p_; + k_i_ = filter_gain_ * target_k_i_ + (1 - filter_gain_) * k_i_; +} + +void ForceExampleController::desiredMassParamCallback( + franka_example_controllers::desired_mass_paramConfig& config, + uint32_t /*level*/) { + target_mass_ = config.desired_mass; + target_k_p_ = config.k_p; + target_k_i_ = config.k_i; +} + +Eigen::Matrix<double, 7, 1> ForceExampleController::saturateTorqueRate( + const Eigen::Matrix<double, 7, 1>& tau_d_calculated, + const Eigen::Matrix<double, 7, 1>& tau_J_d) { // NOLINT (readability-identifier-naming) + Eigen::Matrix<double, 7, 1> tau_d_saturated{}; + for (size_t i = 0; i < 7; i++) { + double difference = tau_d_calculated[i] - tau_J_d[i]; + tau_d_saturated[i] = tau_J_d[i] + std::max(std::min(difference, kDeltaTauMax), -kDeltaTauMax); + } + return tau_d_saturated; +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::ForceExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/force_example_controller.h b/fr3_impedance_controller_real/bak/force_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..1b7eb7d75906e673bbcce9f03694a971fa9bae9b --- /dev/null +++ b/fr3_impedance_controller_real/bak/force_example_controller.h @@ -0,0 +1,61 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> +#include <vector> + +#include <controller_interface/multi_interface_controller.h> +#include <dynamic_reconfigure/server.h> +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> +#include <Eigen/Core> + +#include <franka_example_controllers/desired_mass_paramConfig.h> + +namespace franka_example_controllers { + +class ForceExampleController : public controller_interface::MultiInterfaceController< + franka_hw::FrankaModelInterface, + hardware_interface::EffortJointInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + // Saturation + Eigen::Matrix<double, 7, 1> saturateTorqueRate( + const Eigen::Matrix<double, 7, 1>& tau_d_calculated, + const Eigen::Matrix<double, 7, 1>& tau_J_d); // NOLINT (readability-identifier-naming) + + std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; + std::unique_ptr<franka_hw::FrankaStateHandle> state_handle_; + std::vector<hardware_interface::JointHandle> joint_handles_; + + double desired_mass_{0.0}; + double target_mass_{0.0}; + double k_p_{0.0}; + double k_i_{0.0}; + double target_k_p_{0.0}; + double target_k_i_{0.0}; + double filter_gain_{0.001}; + Eigen::Matrix<double, 7, 1> tau_ext_initial_; + Eigen::Matrix<double, 7, 1> tau_error_; + static constexpr double kDeltaTauMax{1.0}; + + // Dynamic reconfigure + std::unique_ptr<dynamic_reconfigure::Server<franka_example_controllers::desired_mass_paramConfig>> + dynamic_server_desired_mass_param_; + ros::NodeHandle dynamic_reconfigure_desired_mass_param_node_; + void desiredMassParamCallback(franka_example_controllers::desired_mass_paramConfig& config, + uint32_t level); +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/force_example_controller.launch b/fr3_impedance_controller_real/bak/force_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..58c873d96765e1253de439a3063c11de7b0d41b7 --- /dev/null +++ b/fr3_impedance_controller_real/bak/force_example_controller.launch @@ -0,0 +1,10 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="force_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> + <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" required="false" /> +</launch> diff --git a/fr3_impedance_controller_real/bak/joint_impedance_example_controller.cpp b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..607e87da9d919f03cef4925f46b92c8b9ab5e1da --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.cpp @@ -0,0 +1,214 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/joint_impedance_example_controller.h> + +#include <cmath> +#include <memory> + +#include <controller_interface/controller_base.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +#include <franka/robot_state.h> + +namespace franka_example_controllers { + +bool JointImpedanceExampleController::init(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle) { + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("JointImpedanceExampleController: Could not read parameter arm_id"); + return false; + } + if (!node_handle.getParam("radius", radius_)) { + ROS_INFO_STREAM( + "JointImpedanceExampleController: No parameter radius, defaulting to: " << radius_); + } + if (std::fabs(radius_) < 0.005) { + ROS_INFO_STREAM("JointImpedanceExampleController: Set radius to small, defaulting to: " << 0.1); + radius_ = 0.1; + } + + if (!node_handle.getParam("vel_max", vel_max_)) { + ROS_INFO_STREAM( + "JointImpedanceExampleController: No parameter vel_max, defaulting to: " << vel_max_); + } + if (!node_handle.getParam("acceleration_time", acceleration_time_)) { + ROS_INFO_STREAM( + "JointImpedanceExampleController: No parameter acceleration_time, defaulting to: " + << acceleration_time_); + } + + std::vector<std::string> joint_names; + 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!"); + return false; + } + + if (!node_handle.getParam("k_gains", k_gains_) || k_gains_.size() != 7) { + ROS_ERROR( + "JointImpedanceExampleController: Invalid or no k_gain parameters provided, aborting " + "controller init!"); + return false; + } + + if (!node_handle.getParam("d_gains", d_gains_) || d_gains_.size() != 7) { + ROS_ERROR( + "JointImpedanceExampleController: Invalid or no d_gain parameters provided, aborting " + "controller init!"); + return false; + } + + double publish_rate(30.0); + if (!node_handle.getParam("publish_rate", publish_rate)) { + ROS_INFO_STREAM("JointImpedanceExampleController: publish_rate not found. Defaulting to " + << publish_rate); + } + rate_trigger_ = franka_hw::TriggerRate(publish_rate); + + if (!node_handle.getParam("coriolis_factor", coriolis_factor_)) { + ROS_INFO_STREAM("JointImpedanceExampleController: coriolis_factor not found. Defaulting to " + << coriolis_factor_); + } + + auto* model_interface = robot_hw->get<franka_hw::FrankaModelInterface>(); + if (model_interface == nullptr) { + ROS_ERROR_STREAM( + "JointImpedanceExampleController: Error getting model interface from hardware"); + return false; + } + try { + model_handle_ = std::make_unique<franka_hw::FrankaModelHandle>( + model_interface->getHandle(arm_id + "_model")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "JointImpedanceExampleController: Exception getting model handle from interface: " + << ex.what()); + return false; + } + + auto* cartesian_pose_interface = robot_hw->get<franka_hw::FrankaPoseCartesianInterface>(); + if (cartesian_pose_interface == nullptr) { + ROS_ERROR_STREAM( + "JointImpedanceExampleController: Error getting cartesian pose interface from hardware"); + return false; + } + try { + cartesian_pose_handle_ = std::make_unique<franka_hw::FrankaCartesianPoseHandle>( + cartesian_pose_interface->getHandle(arm_id + "_robot")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "JointImpedanceExampleController: Exception getting cartesian pose handle from interface: " + << ex.what()); + return false; + } + + auto* effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); + if (effort_joint_interface == nullptr) { + ROS_ERROR_STREAM( + "JointImpedanceExampleController: Error getting effort joint interface from hardware"); + return false; + } + for (size_t i = 0; i < 7; ++i) { + try { + 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()); + return false; + } + } + torques_publisher_.init(node_handle, "torque_comparison", 1); + + std::fill(dq_filtered_.begin(), dq_filtered_.end(), 0); + + return true; +} + +void JointImpedanceExampleController::starting(const ros::Time& /*time*/) { + initial_pose_ = cartesian_pose_handle_->getRobotState().O_T_EE_d; +} + +void JointImpedanceExampleController::update(const ros::Time& /*time*/, + const ros::Duration& period) { + if (vel_current_ < vel_max_) { + vel_current_ += period.toSec() * std::fabs(vel_max_ / acceleration_time_); + } + vel_current_ = std::fmin(vel_current_, vel_max_); + + angle_ += period.toSec() * vel_current_ / std::fabs(radius_); + if (angle_ > 2 * M_PI) { + angle_ -= 2 * M_PI; + } + + double delta_y = radius_ * (1 - std::cos(angle_)); + double delta_z = radius_ * std::sin(angle_); + + std::array<double, 16> pose_desired = initial_pose_; + pose_desired[13] += delta_y; + pose_desired[14] += delta_z; + cartesian_pose_handle_->setCommand(pose_desired); + + franka::RobotState robot_state = cartesian_pose_handle_->getRobotState(); + std::array<double, 7> coriolis = model_handle_->getCoriolis(); + std::array<double, 7> gravity = model_handle_->getGravity(); + + 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_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). + std::array<double, 7> tau_d_saturated = saturateTorqueRate(tau_d_calculated, robot_state.tau_J_d); + + for (size_t i = 0; i < 7; ++i) { + joint_handles_[i].setCommand(tau_d_saturated[i]); + } + + if (rate_trigger_() && torques_publisher_.trylock()) { + std::array<double, 7> tau_j = robot_state.tau_J; + std::array<double, 7> tau_error; + double error_rms(0.0); + for (size_t i = 0; i < 7; ++i) { + tau_error[i] = last_tau_d_[i] - tau_j[i]; + error_rms += std::sqrt(std::pow(tau_error[i], 2.0)) / 7.0; + } + torques_publisher_.msg_.root_mean_square_error = error_rms; + for (size_t i = 0; i < 7; ++i) { + torques_publisher_.msg_.tau_commanded[i] = last_tau_d_[i]; + torques_publisher_.msg_.tau_error[i] = tau_error[i]; + torques_publisher_.msg_.tau_measured[i] = tau_j[i]; + } + torques_publisher_.unlockAndPublish(); + } + + for (size_t i = 0; i < 7; ++i) { + last_tau_d_[i] = tau_d_saturated[i] + gravity[i]; + } +} + +std::array<double, 7> JointImpedanceExampleController::saturateTorqueRate( + const std::array<double, 7>& tau_d_calculated, + const std::array<double, 7>& tau_J_d) { // NOLINT (readability-identifier-naming) + std::array<double, 7> tau_d_saturated{}; + for (size_t i = 0; i < 7; i++) { + double difference = tau_d_calculated[i] - tau_J_d[i]; + tau_d_saturated[i] = tau_J_d[i] + std::max(std::min(difference, kDeltaTauMax), -kDeltaTauMax); + } + return tau_d_saturated; +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::JointImpedanceExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/joint_impedance_example_controller.h b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..526629a463dfbd43e530978543afe166976b202f --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.h @@ -0,0 +1,60 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> +#include <vector> + +#include <controller_interface/multi_interface_controller.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <realtime_tools/realtime_publisher.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_example_controllers/JointTorqueComparison.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/trigger_rate.h> + +namespace franka_example_controllers { + +class JointImpedanceExampleController : public controller_interface::MultiInterfaceController< + franka_hw::FrankaModelInterface, + hardware_interface::EffortJointInterface, + franka_hw::FrankaPoseCartesianInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + // Saturation + std::array<double, 7> saturateTorqueRate( + const std::array<double, 7>& tau_d_calculated, + const std::array<double, 7>& tau_J_d); // NOLINT (readability-identifier-naming) + + std::unique_ptr<franka_hw::FrankaCartesianPoseHandle> cartesian_pose_handle_; + std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; + std::vector<hardware_interface::JointHandle> joint_handles_; + + static constexpr double kDeltaTauMax{1.0}; + double radius_{0.1}; + double acceleration_time_{2.0}; + double vel_max_{0.05}; + 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}; + std::array<double, 7> last_tau_d_{}; + realtime_tools::RealtimePublisher<JointTorqueComparison> torques_publisher_; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/joint_impedance_example_controller.launch b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..c624359a9ee8a112e23ad5efc420e62c30c8f429 --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_impedance_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_impedance_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/joint_position_example_controller.cpp b/fr3_impedance_controller_real/bak/joint_position_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3ba12b8d80072bc1de24d83c334ed3d23115507f --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_position_example_controller.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/joint_position_example_controller.h> + +#include <cmath> + +#include <controller_interface/controller_base.h> +#include <hardware_interface/hardware_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool JointPositionExampleController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + position_joint_interface_ = robot_hardware->get<hardware_interface::PositionJointInterface>(); + if (position_joint_interface_ == nullptr) { + ROS_ERROR( + "JointPositionExampleController: Error getting position joint interface from hardware!"); + return false; + } + std::vector<std::string> joint_names; + if (!node_handle.getParam("joint_names", joint_names)) { + ROS_ERROR("JointPositionExampleController: Could not parse joint names"); + } + if (joint_names.size() != 7) { + ROS_ERROR_STREAM("JointPositionExampleController: Wrong number of joint names, got " + << joint_names.size() << " instead of 7 names!"); + return false; + } + position_joint_handles_.resize(7); + for (size_t i = 0; i < 7; ++i) { + try { + position_joint_handles_[i] = position_joint_interface_->getHandle(joint_names[i]); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "JointPositionExampleController: Exception getting joint handles: " << e.what()); + return false; + } + } + + std::array<double, 7> q_start{{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(position_joint_handles_[i].getPosition() - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "JointPositionExampleController: Robot is not in the expected starting position for " + "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " + "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); + return false; + } + } + + return true; +} + +void JointPositionExampleController::starting(const ros::Time& /* time */) { + for (size_t i = 0; i < 7; ++i) { + initial_pose_[i] = position_joint_handles_[i].getPosition(); + } + elapsed_time_ = ros::Duration(0.0); +} + +void JointPositionExampleController::update(const ros::Time& /*time*/, + const ros::Duration& period) { + elapsed_time_ += period; + + double delta_angle = M_PI / 16 * (1 - std::cos(M_PI / 5.0 * elapsed_time_.toSec())) * 0.2; + for (size_t i = 0; i < 7; ++i) { + if (i == 4) { + position_joint_handles_[i].setCommand(initial_pose_[i] - delta_angle); + } else { + position_joint_handles_[i].setCommand(initial_pose_[i] + delta_angle); + } + } +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::JointPositionExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/joint_position_example_controller.h b/fr3_impedance_controller_real/bak/joint_position_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..414885106b372223a8b43b951668c5d47efc3271 --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_position_example_controller.h @@ -0,0 +1,31 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <array> +#include <string> +#include <vector> + +#include <controller_interface/multi_interface_controller.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +namespace franka_example_controllers { + +class JointPositionExampleController : public controller_interface::MultiInterfaceController< + hardware_interface::PositionJointInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void starting(const ros::Time&) override; + void update(const ros::Time&, const ros::Duration& period) override; + + private: + hardware_interface::PositionJointInterface* position_joint_interface_; + std::vector<hardware_interface::JointHandle> position_joint_handles_; + ros::Duration elapsed_time_; + std::array<double, 7> initial_pose_{}; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/joint_position_example_controller.launch b/fr3_impedance_controller_real/bak/joint_position_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..565fc885e25aa9c3e33e77ab026bf90df8cae51d --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_position_example_controller.launch @@ -0,0 +1,8 @@ +<?xml version="1.0" ?> +<launch> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <arg name="arm_id" default="fr3"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_position_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/joint_velocity_example_controller.cpp b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d9274c8b7cc0037049f29b661beb776d59d8fa2 --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/joint_velocity_example_controller.h> + +#include <cmath> + +#include <controller_interface/controller_base.h> +#include <hardware_interface/hardware_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool JointVelocityExampleController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + velocity_joint_interface_ = robot_hardware->get<hardware_interface::VelocityJointInterface>(); + if (velocity_joint_interface_ == nullptr) { + ROS_ERROR( + "JointVelocityExampleController: Error getting velocity joint interface from hardware!"); + return false; + } + + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("JointVelocityExampleController: Could not get parameter arm_id"); + return false; + } + + std::vector<std::string> joint_names; + if (!node_handle.getParam("joint_names", joint_names)) { + ROS_ERROR("JointVelocityExampleController: Could not parse joint names"); + } + if (joint_names.size() != 7) { + ROS_ERROR_STREAM("JointVelocityExampleController: Wrong number of joint names, got " + << joint_names.size() << " instead of 7 names!"); + return false; + } + velocity_joint_handles_.resize(7); + for (size_t i = 0; i < 7; ++i) { + try { + velocity_joint_handles_[i] = velocity_joint_interface_->getHandle(joint_names[i]); + } catch (const hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "JointVelocityExampleController: Exception getting joint handles: " << ex.what()); + return false; + } + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("JointVelocityExampleController: Could not get state interface from hardware"); + return false; + } + + try { + auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + std::array<double, 7> q_start{{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "JointVelocityExampleController: Robot is not in the expected starting position for " + "running this example. Run `roslaunch franka_example_controllers move_to_start.launch " + "robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` first."); + return false; + } + } + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "JointVelocityExampleController: Exception getting state handle: " << e.what()); + return false; + } + + return true; +} + +void JointVelocityExampleController::starting(const ros::Time& /* time */) { + elapsed_time_ = ros::Duration(0.0); +} + +void JointVelocityExampleController::update(const ros::Time& /* time */, + const ros::Duration& period) { + elapsed_time_ += period; + + ros::Duration time_max(8.0); + double omega_max = 0.1; + double cycle = std::floor( + std::pow(-1.0, (elapsed_time_.toSec() - std::fmod(elapsed_time_.toSec(), time_max.toSec())) / + time_max.toSec())); + double omega = cycle * omega_max / 2.0 * + (1.0 - std::cos(2.0 * M_PI / time_max.toSec() * elapsed_time_.toSec())); + + for (auto joint_handle : velocity_joint_handles_) { + joint_handle.setCommand(omega); + } +} + +void JointVelocityExampleController::stopping(const ros::Time& /*time*/) { + // WARNING: DO NOT SEND ZERO VELOCITIES HERE AS IN CASE OF ABORTING DURING MOTION + // A JUMP TO ZERO WILL BE COMMANDED PUTTING HIGH LOADS ON THE ROBOT. LET THE DEFAULT + // BUILT-IN STOPPING BEHAVIOR SLOW DOWN THE ROBOT. +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::JointVelocityExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/joint_velocity_example_controller.h b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..3c20999d8578a5bf1b1d073bedf24d95d3bbf08e --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.h @@ -0,0 +1,32 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <string> +#include <vector> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_state_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +namespace franka_example_controllers { + +class JointVelocityExampleController : public controller_interface::MultiInterfaceController< + hardware_interface::VelocityJointInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void update(const ros::Time&, const ros::Duration& period) override; + void starting(const ros::Time&) override; + void stopping(const ros::Time&) override; + + private: + hardware_interface::VelocityJointInterface* velocity_joint_interface_; + std::vector<hardware_interface::JointHandle> velocity_joint_handles_; + ros::Duration elapsed_time_; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/joint_velocity_example_controller.launch b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..ff17fdd2c3238ae98a82e1c129794bb55fd2b01d --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_velocity_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="joint_velocity_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/joint_wall.cpp b/fr3_impedance_controller_real/bak/joint_wall.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2138bf778a2daf2394ba68992c1d54196775297 --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_wall.cpp @@ -0,0 +1,155 @@ +// Copyright (c) 2022 Franka Emika GmbH +#include <franka_example_controllers/joint_wall.h> + +#include <ros/ros.h> + +#include <cmath> +#include <iostream> +#include <sstream> + +namespace franka_example_controllers { + +JointWall::JointWall(const double soft_upper_joint_position_limit, + const double soft_lower_joint_position_limit, + const double PD_zone_width, // NOLINT (readability-identifier-naming) + const double D_zone_width, // NOLINT (readability-identifier-naming) + const double PD_zone_stiffness, // NOLINT (readability-identifier-naming) + const double PD_zone_damping, // NOLINT (readability-identifier-naming) + const double D_zone_damping) // NOLINT (readability-identifier-naming) + : soft_upper_joint_position_limit_(soft_upper_joint_position_limit), + soft_lower_joint_position_limit_(soft_lower_joint_position_limit), + PD_zone_width_(PD_zone_width), + D_zone_width_(D_zone_width), + PD_zone_stiffness_(PD_zone_stiffness), + PD_zone_damping_(PD_zone_damping), + D_zone_damping_(D_zone_damping) { + PD_zone_width_ = positiveCheck(PD_zone_width); + D_zone_width_ = positiveCheck(D_zone_width); + PD_zone_stiffness_ = positiveCheck(PD_zone_stiffness); + PD_zone_damping_ = positiveCheck(PD_zone_damping); + D_zone_damping_ = positiveCheck(D_zone_damping); +}; + +double JointWall::computeTorque(const double q, const double dq) { + init(q, dq); + adjustMovingWall(q, dq); + + double D_zone_boundary_max = // NOLINT (readability-identifier-naming) + soft_upper_joint_position_limit_ - zone_width_scale_ * (PD_zone_width_ + D_zone_width_); + double PD_zone_boundary_max = // NOLINT (readability-identifier-naming) + soft_upper_joint_position_limit_ - zone_width_scale_ * PD_zone_width_; + double D_zone_boundary_min = // NOLINT (readability-identifier-naming) + soft_lower_joint_position_limit_ + zone_width_scale_ * (PD_zone_width_ + D_zone_width_); + double PD_zone_boundary_min = // NOLINT (readability-identifier-naming) + soft_lower_joint_position_limit_ + zone_width_scale_ * PD_zone_width_; + + double torque = 0; + if (inRange(D_zone_boundary_max, PD_zone_boundary_max, q) || + inRange(PD_zone_boundary_min, D_zone_boundary_min, q)) { + // In D zone + torque = -D_zone_damping_ * dq; + } else if (q > PD_zone_boundary_max) { + // In PD zone max + torque = -PD_zone_damping_ * dq + PD_zone_stiffness_ * (PD_zone_boundary_max - q); + } else if (q < PD_zone_boundary_min) { + // In PD zone min + torque = -PD_zone_damping_ * dq + PD_zone_stiffness_ * (PD_zone_boundary_min - q); + } + + return torque; +} + +void JointWall::reset() { + initialized_ = false; +} + +bool JointWall::inRange(double low, double high, double x) { + return (low <= x && x <= high); +}; + +void JointWall::init(const double q, const double dq) { + if (initialized_) { + return; + } + + if (q < soft_lower_joint_position_limit_ || q > soft_upper_joint_position_limit_) { + std::stringstream ss; + ss << "q " << q << " is beyond the joint wall: [" << soft_lower_joint_position_limit_ << ", " + << soft_upper_joint_position_limit_ << "]"; + throw std::runtime_error(ss.str().c_str()); + } + + switch (getMotionInWall(q, dq)) { + case MotionInWall::EnteringNormal: + moving_wall_ = false; + break; + case MotionInWall::PenetratingLowerLimit: + case MotionInWall::LeavingLowerLimit: + zone_width_scale_ = + fabs(q - soft_lower_joint_position_limit_) / (PD_zone_width_ + D_zone_width_); + moving_wall_ = true; + break; + case MotionInWall::PenetratingUpperLimit: + case MotionInWall::LeavingUpperLimit: + zone_width_scale_ = + fabs(q - soft_upper_joint_position_limit_) / (PD_zone_width_ + D_zone_width_); + moving_wall_ = true; + break; + } + initialized_ = true; +} + +void JointWall::adjustMovingWall(const double q, const double dq) { + if (!moving_wall_) { + return; + } + double new_scale; + switch (getMotionInWall(q, dq)) { + case MotionInWall::EnteringNormal: + moving_wall_ = false; + zone_width_scale_ = 1; + break; + case MotionInWall::LeavingLowerLimit: + new_scale = fabs(q - soft_lower_joint_position_limit_) / (PD_zone_width_ + D_zone_width_); + zone_width_scale_ = fmax(zone_width_scale_, new_scale); + break; + case MotionInWall::LeavingUpperLimit: + new_scale = fabs(q - soft_upper_joint_position_limit_) / (PD_zone_width_ + D_zone_width_); + zone_width_scale_ = fmax(zone_width_scale_, new_scale); + break; + case MotionInWall::PenetratingLowerLimit: + case MotionInWall::PenetratingUpperLimit: + break; + } +} + +double JointWall::positiveCheck(double value) { + if (value < 0) { + ROS_WARN_THROTTLE( + 1, "JointWall expects positive parameters, but got negative. Using its absolute value."); + value = fabs(value); + } + return value; +} + +JointWall::MotionInWall JointWall::getMotionInWall(const double q, const double dq) const { + double D_zone_boundary_max = // NOLINT (readability-identifier-naming) + soft_upper_joint_position_limit_ - PD_zone_width_ - D_zone_width_; + double D_zone_boundary_min = // NOLINT (readability-identifier-naming) + soft_lower_joint_position_limit_ + PD_zone_width_ + D_zone_width_; + if (q < D_zone_boundary_min) { + if (dq <= 0) { + return MotionInWall::PenetratingLowerLimit; + } + return MotionInWall::LeavingLowerLimit; + } + if (q > D_zone_boundary_max) { + if (dq >= 0) { + return MotionInWall::PenetratingUpperLimit; + } + return MotionInWall::LeavingUpperLimit; + } + return MotionInWall::EnteringNormal; +} + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/joint_wall.h b/fr3_impedance_controller_real/bak/joint_wall.h new file mode 100644 index 0000000000000000000000000000000000000000..753c81bcdbbc056a848a6e9fc0e08061d8765b21 --- /dev/null +++ b/fr3_impedance_controller_real/bak/joint_wall.h @@ -0,0 +1,199 @@ +// Copyright (c) 2022 Franka Emika GmbH +#pragma once + +#include <array> +#include <memory> + +// clang-format off +/** + * @file joint_wall.h + * Contains functions for calculating torques generated by virtual walls. + |<---- PD_zone_width ------>|<---D_zone_width--->| |<---D_zone_width--->|<--- PD_zone_width --->| + |:::::::::::::::::::::::::::|- - - - - - - - - - | | - - - - - - - - - -|:::::::::::::::::::::::| + ^ soft_lower_joint_position_limit normal ^ range soft_upper_joint_position_limit ^ + PD_zone_boundary_min ^ ^ PD_zone_boundary_max + D_zone_boundary_min ^ ^ D_zone_boundary_max +*/ +// clang-format on + +namespace franka_example_controllers { + +/// A class that offers an implementation of a virtual wall for a single joint. +class JointWall { + public: + /** + * Creates a JointWall instance with default params. + */ + JointWall() = delete; + + /** + * Creates a JointWall instance with configurable parameters. + * @param[in] soft_upper_joint_position_limit (rad) + * @param[in] soft_lower_joint_position_limit (rad) + * @param[in] PD_zone_width (meter) + * @param[in] D_zone_width (meter) + * @param[in] PD_zone_stiffness (N*meter/rad) + * @param[in] PD_zone_damping (N*meter*s/rad) + * @param[in] D_zone_damping (N*meter*s/rad) + */ + JointWall(double soft_upper_joint_position_limit, + double soft_lower_joint_position_limit, + double PD_zone_width, + double D_zone_width, + double PD_zone_stiffness, + double PD_zone_damping, + double D_zone_damping); + + /** + * Computes the torque with given q and dq. Be aware that the torque is also affected by previous + * states. + * @param[in] q current joint position. + * @param[in] dq the current joint velocity. + * @return the resulting torque + */ + double computeTorque(double q, double dq); + + /** + * Resets the initialized flag to false. After calling reset, the next call to computeTorque + * resets the internal states for joint position and velocity (q, dq). Call this method before + * restarting your controller, e.g. when the position might have changed during control pauses due + * to guiding. + */ + void reset(); + + private: + /** + * Indicates the status of moving wall, which occurs after initializing the state inside a wall. + */ + enum class MotionInWall { + EnteringNormal, + PenetratingLowerLimit, + LeavingLowerLimit, + PenetratingUpperLimit, + LeavingUpperLimit + }; + + // Joint wall parameters + double soft_upper_joint_position_limit_{0}; + double soft_lower_joint_position_limit_{0}; + double PD_zone_width_{0}; + double D_zone_width_{0}; + double PD_zone_stiffness_{0}; + double PD_zone_damping_{0}; + double D_zone_damping_{0}; + + bool initialized_{false}; // Internal states q, dq will be reset to the current states in + // computeTorque if initialized_ = false; + + // Indicates whether the joint wall is still moving, which occurs after initializing the state + // inside joint wall. + bool moving_wall_{false}; + + double zone_width_scale_{1}; + + /** + * Checks if x is in range [low, high] + * @param[in] low lower limit of the range. + * @param[in] high upper limit of the range. + * @param[in] x value to check. + * @return true if in range, false otherwise. + */ + static bool inRange(double low, double high, double x); + + /** + * Check if the input is positive number, if not print error and return its abs + * @param[in] value The value to check. + * @return the absolute value of the value. + */ + static double positiveCheck(double value); + + /** + * Initializes the joint wall computation with initial states. + * @param[in] q the current joint position. + * @param[in] dq the current joint velocity. + */ + void init(double q, double dq); + + /** + * Moves the wall with given state if the state is initialized inside the wall + * @param[in] q the current joint position. + * @param[in] dq the current joint velocity. + */ + void adjustMovingWall(double q, double dq); + + /** + * Checks the motion type in joint wall + * @param[in] q the current joint position. + * @param[in] dq the current joint velocity. + */ + MotionInWall getMotionInWall(double q, double dq) const; +}; + +/** + * A class that organizes multiple virtual joint walls. + * @tparam num_dof the number of joints to create virtual walls for. + */ +template <size_t num_dof> +class JointWallContainer { + public: + /** + * Creates a new virtual joint position wall instance. (see joint_wall.h for more details on joint + * wall parameters.) + * + * @param[in] soft_upper_joint_position_limits + * @param[in] soft_lower_joint_position_limits + * @param[in] PD_zone_widths + * @param[in] D_zone_widths + * @param[in] PD_zone_stiffnesses + * @param[in] PD_zone_dampings + * @param[in] D_zone_dampings + */ + JointWallContainer(const std::array<double, num_dof>& soft_upper_joint_position_limits, + const std::array<double, num_dof>& soft_lower_joint_position_limits, + const std::array<double, num_dof>& PD_zone_widths, + const std::array<double, num_dof>& D_zone_widths, + const std::array<double, num_dof>& PD_zone_stiffnesses, + const std::array<double, num_dof>& PD_zone_dampings, + const std::array<double, num_dof>& D_zone_dampings) { + for (size_t i = 0; i < num_dof; i++) { + joint_walls_.at(i) = std::make_unique<JointWall>( + soft_upper_joint_position_limits[i], soft_lower_joint_position_limits[i], + PD_zone_widths[i], D_zone_widths[i], PD_zone_stiffnesses[i], PD_zone_dampings[i], + D_zone_dampings[i]); + } + } + + JointWallContainer() = delete; + + /** + * Computes the torques generated by virtual walls. + * @param[in] q the current joint positions. + * @param[in] dq the current joint velocities. + * @return the repelling torques/efforts from the virtual wall. + */ + std::array<double, num_dof> computeTorque(const std::array<double, num_dof>& q, + const std::array<double, num_dof>& dq) { + std::array<double, num_dof> torque; + for (size_t i = 0; i < num_dof; i++) { + torque[i] = joint_walls_[i]->computeTorque(q[i], dq[i]); + }; + return torque; + } + + /** + * Resets the initialized flags of all walls to false. After calling reset, the next call to + * computeTorque resets the internal states for joint position and velocity (q, dq). Call this + * method before restarting your controller, e.g. when the position might have changed during + * control pauses due to guiding. + */ + void reset() { + for (auto& jw : joint_walls_) { + jw->reset(); + } + } + + private: + std::array<std::unique_ptr<JointWall>, num_dof> joint_walls_; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/mainpage.dox b/fr3_impedance_controller_real/bak/mainpage.dox new file mode 100644 index 0000000000000000000000000000000000000000..941d0bf97714038b58c39c7dcd816e901e22c023 --- /dev/null +++ b/fr3_impedance_controller_real/bak/mainpage.dox @@ -0,0 +1,6 @@ +/** + * @mainpage + * @htmlinclude "manifest.html" + * + * Overview page for Franka Emika research robots: https://frankaemika.github.io + */ diff --git a/fr3_impedance_controller_real/bak/model_example_controller.cpp b/fr3_impedance_controller_real/bak/model_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b67f2416e7473626a91515f551c81c5d8209bb82 --- /dev/null +++ b/fr3_impedance_controller_real/bak/model_example_controller.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE + +#include <franka_example_controllers/model_example_controller.h> + +#include <algorithm> +#include <array> +#include <cstring> +#include <iterator> +#include <memory> + +#include <controller_interface/controller_base.h> +#include <hardware_interface/hardware_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/franka_state_interface.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 ModelExampleController::init(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle) { + franka_state_interface_ = robot_hw->get<franka_hw::FrankaStateInterface>(); + if (franka_state_interface_ == nullptr) { + ROS_ERROR("ModelExampleController: Could not get Franka state interface from hardware"); + return false; + } + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("ModelExampleController: Could not read parameter arm_id"); + return false; + } + model_interface_ = robot_hw->get<franka_hw::FrankaModelInterface>(); + if (model_interface_ == nullptr) { + ROS_ERROR_STREAM("ModelExampleController: Error getting model interface from hardware"); + 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( + "ModelExampleController: Exception getting franka state handle: " << ex.what()); + return false; + } + + try { + model_handle_ = std::make_unique<franka_hw::FrankaModelHandle>( + model_interface_->getHandle(arm_id + "_model")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + ROS_ERROR_STREAM( + "ModelExampleController: Exception getting model handle from interface: " << ex.what()); + return false; + } + return true; +} + +void ModelExampleController::update(const ros::Time& /*time*/, const ros::Duration& /*period*/) { + if (rate_trigger_()) { + std::array<double, 49> mass = model_handle_->getMass(); + std::array<double, 7> coriolis = model_handle_->getCoriolis(); + std::array<double, 7> gravity = model_handle_->getGravity(); + std::array<double, 16> pose = model_handle_->getPose(franka::Frame::kJoint4); + std::array<double, 42> joint4_body_jacobian = + model_handle_->getBodyJacobian(franka::Frame::kJoint4); + std::array<double, 42> endeffector_zero_jacobian = + model_handle_->getZeroJacobian(franka::Frame::kEndEffector); + + ROS_INFO("--------------------------------------------------"); + ROS_INFO_STREAM("mass :" << mass); + ROS_INFO_STREAM("coriolis: " << coriolis); + ROS_INFO_STREAM("gravity :" << gravity); + ROS_INFO_STREAM("joint_pose :" << pose); + ROS_INFO_STREAM("joint4_body_jacobian :" << joint4_body_jacobian); + ROS_INFO_STREAM("joint_zero_jacobian :" << endeffector_zero_jacobian); + } +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::ModelExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/model_example_controller.h b/fr3_impedance_controller_real/bak/model_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..e1b4aef2dd18c45fe7388db300f6a5c5f78704fb --- /dev/null +++ b/fr3_impedance_controller_real/bak/model_example_controller.h @@ -0,0 +1,34 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/franka_state_interface.h> +#include <franka_hw/trigger_rate.h> + +namespace franka_example_controllers { + +class ModelExampleController + : public controller_interface::MultiInterfaceController<franka_hw::FrankaModelInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) override; + void update(const ros::Time&, const ros::Duration&) override; + + private: + franka_hw::FrankaStateInterface* franka_state_interface_; + std::unique_ptr<franka_hw::FrankaStateHandle> franka_state_handle_; + franka_hw::FrankaModelInterface* model_interface_; + std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; + franka_hw::TriggerRate rate_trigger_{1.0}; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/model_example_controller.launch b/fr3_impedance_controller_real/bak/model_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..61ea5ef7f8825b7bc021b24ffaec8ca7a0e138a4 --- /dev/null +++ b/fr3_impedance_controller_real/bak/model_example_controller.launch @@ -0,0 +1,9 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="model_example_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/move_to_start.launch b/fr3_impedance_controller_real/bak/move_to_start.launch new file mode 100644 index 0000000000000000000000000000000000000000..fd9ce503201cc9a59385506eca825abf3deee93d --- /dev/null +++ b/fr3_impedance_controller_real/bak/move_to_start.launch @@ -0,0 +1,30 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot_ip" /> + <arg name="arm_id" default="panda" /> + <arg name="transmission" default="effort" doc="The type of position control to use (either 'position' or 'effort')" /> + + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"> + <arg name="load_gripper" value="false" /> + </include> + + <node name="controller_spawner" + pkg="controller_manager" + type="spawner" + respawn="false" + output="screen" + args="$(arg transmission)_joint_trajectory_controller"> + </node> + + <node name="move_to_start" + pkg="franka_example_controllers" + type="move_to_start.py" + output="screen" + required="true"> + <rosparam file="$(find franka_control)/config/start_pose.yaml" subst_value="true" /> + <remap from="~follow_joint_trajectory" to="$(arg transmission)_joint_trajectory_controller/follow_joint_trajectory" /> + <remap from="~joint_states" to="franka_state_controller/joint_states" /> + <param name="max_dq" value="0.2" /> <!-- [rad/s] --> + </node> + +</launch> diff --git a/fr3_impedance_controller_real/bak/msg/JointTorqueComparison.msg b/fr3_impedance_controller_real/bak/msg/JointTorqueComparison.msg new file mode 100644 index 0000000000000000000000000000000000000000..c5197324ed2d16df92985ebe664fe9cc96da1d00 --- /dev/null +++ b/fr3_impedance_controller_real/bak/msg/JointTorqueComparison.msg @@ -0,0 +1,4 @@ +float64[7] tau_error +float64[7] tau_commanded +float64[7] tau_measured +float64 root_mean_square_error diff --git a/fr3_impedance_controller_real/bak/package_bak.xml b/fr3_impedance_controller_real/bak/package_bak.xml new file mode 100644 index 0000000000000000000000000000000000000000..297f2003c5617cd900dc32956aec47fee2b122c8 --- /dev/null +++ b/fr3_impedance_controller_real/bak/package_bak.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<package format="2"> + <name>fr3_impedance_controller_real</name> + <version>0.0.1</version> + <description>Impedance controller for the Franka Emika FR3</description> + <maintainer email="todo@todo.com"></maintainer> + <license>Apache 2.0</license> + + + <buildtool_depend>catkin</buildtool_depend> + + <build_depend>message_generation</build_depend> + <build_depend>eigen</build_depend> + + <build_export_depend>message_runtime</build_export_depend> + + <depend>controller_interface</depend> + <depend>dynamic_reconfigure</depend> + <depend>eigen_conversions</depend> + <depend>franka_hw</depend> + <depend>franka_gripper</depend> + <depend>franka_example_controllers</depend> + <depend>geometry_msgs</depend> + <depend>hardware_interface</depend> + <depend>joint_limits_interface</depend> + <depend>tf</depend> + <depend>tf_conversions</depend> + <depend>libfranka</depend> + <depend>pluginlib</depend> + <depend>realtime_tools</depend> + <depend>roscpp</depend> + <depend>urdf</depend> + <depend>sensor_msgs</depend> + <depend>visualization_msgs</depend> + + <exec_depend>franka_control</exec_depend> + <exec_depend>franka_description</exec_depend> + <exec_depend>message_runtime</exec_depend> + <exec_depend>rospy</exec_depend> + + <export> + <controller_interface plugin="${prefix}/fr3_impedance_controller_real_plugin.xml" /> + </export> +</package> diff --git a/fr3_impedance_controller_real/bak/robot.rviz b/fr3_impedance_controller_real/bak/robot.rviz new file mode 100644 index 0000000000000000000000000000000000000000..f4f6170c8eb3e76c333cc2b6cd87abaf7fea25b5 --- /dev/null +++ b/fr3_impedance_controller_real/bak/robot.rviz @@ -0,0 +1,266 @@ +Panels: + - Class: rviz/Displays + Help Height: 89 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /RobotModel1 + Splitter Ratio: 0.5 + Tree Height: 278 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Name: Time + SyncMode: 0 + SyncSource: Image +Preferences: + PromptSaveOnExit: true +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: <Fixed Frame> + Value: true + - Alpha: 0.20000000298023224 + Class: rviz/RobotModel + Collision Enabled: false + Enabled: true + Links: + All Links Enabled: true + Expand Joint Details: false + Expand Link Details: false + Expand Tree: false + Link Tree Style: Links in Alphabetic Order + fr3_hand: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_hand_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_hand_tcp: + Alpha: 1 + Show Axes: false + Show Trail: false + fr3_leftfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link0: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link0_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link1: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link1_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link2: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link2_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link3: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link3_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link4: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link4_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link5: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link5_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link6: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link6_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link7: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link7_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + fr3_link8: + Alpha: 1 + Show Axes: false + Show Trail: false + fr3_rightfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Name: RobotModel + Robot Description: robot_description + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: visualization_marker_array + Name: MarkerArray + Namespaces: + {} + Queue Size: 100 + Value: true + - Class: rviz/Image + Enabled: true + Image Topic: /camera/color/image_raw + Max Value: 1 + Median window: 5 + Min Value: 0 + Name: Image + Normalize Range: true + Queue Size: 2 + Transport Hint: raw + Unreliable: false + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Default Light: true + Fixed Frame: fr3_link0 + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/MoveCamera + - Class: rviz/Select + - Class: rviz/FocusCamera + - Class: rviz/Measure + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Class: rviz/Orbit + Distance: 0.6237555146217346 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Field of View: 0.7853981852531433 + Focal Point: + X: 0.363277792930603 + Y: 0.005851757247000933 + Z: 0.04891345649957657 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.16539791226387024 + Target Frame: <Fixed Frame> + Yaw: 1.2904071807861328 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1163 + Hide Left Dock: false + Hide Right Dock: true + Image: + collapsed: false + QMainWindow State: 000000ff00000000fd000000040000000000000334000003edfc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000001ac000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000001ef0000023b0000001600ffffff000000010000010f000003edfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d000003ed000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007800000003efc0100000002fb0000000800540069006d0065010000000000000780000003bc00fffffffb0000000800540069006d0065010000000000000450000000000000000000000446000003ed00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: true + Width: 1920 + X: 2560 + Y: 240 diff --git a/fr3_impedance_controller_real/bak/rosdoc.yaml b/fr3_impedance_controller_real/bak/rosdoc.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96ee597ef5cacd0f223f676c738f396f0810b78c --- /dev/null +++ b/fr3_impedance_controller_real/bak/rosdoc.yaml @@ -0,0 +1,2 @@ +- builder: doxygen + javadoc_autobrief: YES diff --git a/fr3_impedance_controller_real/launch/rviz/franka_description_with_marker.rviz b/fr3_impedance_controller_real/bak/rviz/franka_description_with_marker.rviz similarity index 100% rename from fr3_impedance_controller_real/launch/rviz/franka_description_with_marker.rviz rename to fr3_impedance_controller_real/bak/rviz/franka_description_with_marker.rviz diff --git a/fr3_impedance_controller_real/bak/rviz/franka_dual_description_with_marker.rviz b/fr3_impedance_controller_real/bak/rviz/franka_dual_description_with_marker.rviz new file mode 100644 index 0000000000000000000000000000000000000000..bdd4b593a530fb3c89e7423473e06f7e7635fa04 --- /dev/null +++ b/fr3_impedance_controller_real/bak/rviz/franka_dual_description_with_marker.rviz @@ -0,0 +1,281 @@ +Panels: + - Class: rviz/Displays + Help Height: 0 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /RobotModel1 + - /InteractiveMarkers1 + Splitter Ratio: 0.655555546 + Tree Height: 820 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.588679016 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.0299999993 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: <Fixed Frame> + Value: true + - Class: rviz/TF + Enabled: false + Frame Timeout: 15 + Frames: + All Enabled: true + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: true + Tree: + {} + Update Interval: 0 + Value: false + - Alpha: 1 + Class: rviz/RobotModel + Collision Enabled: false + Enabled: true + Links: + All Links Enabled: true + Expand Joint Details: false + Expand Link Details: false + Expand Tree: false + Link Tree Style: Links in Alphabetic Order + base: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_hand: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_leftfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link0: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link1: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link2: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link3: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link4: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link5: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link6: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link7: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_link8: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_1_rightfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_hand: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_leftfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link0: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link1: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link2: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link3: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link4: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link5: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link6: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link7: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_link8: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + panda_2_rightfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Name: RobotModel + Robot Description: panda_dual/robot_description + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Class: rviz/InteractiveMarkers + Enable Transparency: true + Enabled: true + Name: InteractiveMarkers + Show Axes: true + Show Descriptions: true + Show Visual Aids: true + Update Topic: /panda_dual/target_pose_marker/update + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Default Light: true + Fixed Frame: base + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/MoveCamera + - Class: rviz/Select + - Class: rviz/FocusCamera + - Class: rviz/Measure + - Class: rviz/SetInitialPose + Topic: /initialpose + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Class: rviz/Orbit + Distance: 2.63399172 + Enable Stereo Rendering: + Stereo Eye Separation: 0.0599999987 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0.42157951 + Y: -0.0423400775 + Z: 1.508255 + Focal Shape Fixed Size: true + Focal Shape Size: 0.0500000007 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.00999999978 + Pitch: 0.429795891 + Target Frame: <Fixed Frame> + Value: Orbit (rviz) + Yaw: 6.16679144 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1020 + Hide Left Dock: false + Hide Right Dock: true + QMainWindow State: 000000ff00000000fd00000004000000000000016a00000375fc020000000dfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000006100fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000002800000375000000d700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e006701000001bc000001e20000000000000000fb0000002e004d006f00740069006f006e0050006c0061006e006e0069006e00670020002d00200053006c00690064006500720000000000ffffffff0000000000000000fb000000120020002d00200053006c00690064006500720000000000ffffffff0000000000000000fb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e006701000001ce000001d10000000000000000fb0000000a0049006d00610067006500000001a9000001f50000000000000000000000010000010f00000365fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003f00000365000000ad00fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073f0000003bfc0100000002fb0000000800540069006d006501000000000000073f0000030000fffffffb0000000800540069006d00650100000000000004500000000000000000000005cf0000037500000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: true + Width: 1855 + X: 65 + Y: 28 diff --git a/fr3_impedance_controller_real/bak/rviz/teleop_joint_pd_example.rviz b/fr3_impedance_controller_real/bak/rviz/teleop_joint_pd_example.rviz new file mode 100644 index 0000000000000000000000000000000000000000..4fc200b9bfa79f776f2378c41504d0d81103db43 --- /dev/null +++ b/fr3_impedance_controller_real/bak/rviz/teleop_joint_pd_example.rviz @@ -0,0 +1,396 @@ +Panels: + - Class: rviz/Displays + Help Height: 0 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /RobotModel1 + - /WrenchStampedSlave1 + - /MarkerArray1 + Splitter Ratio: 0.4892857074737549 + Tree Height: 809 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" +Preferences: + PromptSaveOnExit: true +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: <Fixed Frame> + Value: true + - Class: rviz/TF + Enabled: false + Frame Timeout: 15 + Frames: + All Enabled: true + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: true + Tree: + {} + Update Interval: 0 + Value: false + - Alpha: 1 + Class: rviz/RobotModel + Collision Enabled: false + Enabled: true + Links: + All Links Enabled: true + Expand Joint Details: false + Expand Link Details: false + Expand Tree: false + Link Tree Style: Links in Alphabetic Order + base: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_hand: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_hand_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_hand_tcp: + Alpha: 1 + Show Axes: false + Show Trail: false + follower_leftfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link0: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link0_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link1: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link1_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link2: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link2_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link3: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link3_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link4: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link4_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link5: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link5_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link6: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link6_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link7: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link7_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + follower_link8: + Alpha: 1 + Show Axes: false + Show Trail: false + follower_rightfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_hand: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_hand_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_hand_tcp: + Alpha: 1 + Show Axes: false + Show Trail: false + leader_leftfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link0: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link0_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link1: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link1_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link2: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link2_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link3: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link3_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link4: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link4_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link5: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link5_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link6: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link6_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link7: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link7_sc: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + leader_link8: + Alpha: 1 + Show Axes: false + Show Trail: false + leader_rightfinger: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Name: RobotModel + Robot Description: panda_teleop/robot_description + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Alpha: 1 + Arrow Width: 0.20000000298023224 + Class: rviz/WrenchStamped + Enabled: true + Force Arrow Scale: 0.05000000074505806 + Force Color: 204; 51; 51 + Hide Small Values: true + History Length: 1 + Name: WrenchStampedSlave + Topic: /panda_teleop/follower_state_controller/F_ext + Torque Arrow Scale: 0.20000000298023224 + Torque Color: 204; 204; 51 + Unreliable: false + Value: true + - Class: rviz/MarkerArray + Enabled: true + Marker Topic: /panda_teleop/teleop_joint_pd_example_controller/marker_labels + Name: MarkerArray + Namespaces: + basic_shapes: true + Queue Size: 100 + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Default Light: true + Fixed Frame: base + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/MoveCamera + - Class: rviz/Select + - Class: rviz/FocusCamera + - Class: rviz/Measure + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Class: rviz/Orbit + Distance: 4.382266998291016 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: -0.43465375900268555 + Y: 0.19732384383678436 + Z: 0.8964318633079529 + Focal Shape Fixed Size: false + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.3903988003730774 + Target Frame: <Fixed Frame> + Value: Orbit (rviz) + Yaw: 6.2585835456848145 + Saved: ~ +Window Geometry: + Displays: + collapsed: true + Height: 1025 + Hide Left Dock: true + Hide Right Dock: true + QMainWindow State: 000000ff00000000fd0000000400000000000003fd00000366fc020000000dfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073000000003d00000366000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e006701000001bc000001e20000000000000000fb0000002e004d006f00740069006f006e0050006c0061006e006e0069006e00670020002d00200053006c00690064006500720000000000ffffffff0000000000000000fb000000120020002d00200053006c00690064006500720000000000ffffffff0000000000000000fb0000001c004d006f00740069006f006e0050006c0061006e006e0069006e006701000001ce000001d10000000000000000fb0000000a0049006d00610067006500000001a9000001f50000000000000000000000010000010f00000365fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003f00000365000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e100000197000000030000073d0000003bfc0100000002fb0000000800540069006d006501000000000000073d000002eb00fffffffb0000000800540069006d006501000000000000045000000000000000000000073d0000036600000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: true + Width: 1853 + X: 67 + Y: 27 diff --git a/fr3_impedance_controller_real/bak/scripts/dual_arm_interactive_marker.py b/fr3_impedance_controller_real/bak/scripts/dual_arm_interactive_marker.py new file mode 100755 index 0000000000000000000000000000000000000000..a26c2d9094eb142c5ca2280d80587cf48c4370ee --- /dev/null +++ b/fr3_impedance_controller_real/bak/scripts/dual_arm_interactive_marker.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python +""" This simple script creates an interactive marker for changing desired centering pose of + two the dual_panda_cartesian_impedance_example_controller. It features also resetting the + marker to current centering pose between the left and the right endeffector. +""" + +import rospy +import argparse + +from interactive_markers.interactive_marker_server import \ + InteractiveMarkerServer, InteractiveMarkerFeedback +from visualization_msgs.msg import InteractiveMarker, \ + InteractiveMarkerControl, Marker +from franka_msgs.msg import FrankaState +from geometry_msgs.msg import PoseStamped + +marker_pose = PoseStamped() + +has_error = False +left_has_error = False +right_has_error = False + +pose_pub = None + + +def make_sphere(scale=0.3): + """ + This function returns sphere marker for 3D translational movements. + :param scale: scales the size of the sphere + :return: sphere marker + """ + marker = Marker() + marker.type = Marker.SPHERE + marker.scale.x = scale * 0.45 + marker.scale.y = scale * 0.45 + marker.scale.z = scale * 0.45 + marker.color.r = 0.5 + marker.color.g = 0.5 + marker.color.b = 0.5 + marker.color.a = 1.0 + return marker + + +def publish_target_pose(): + """ + This function publishes desired centering pose which the controller will subscribe to. + :return: None + """ + marker_pose.header.stamp = rospy.Time(0) + pose_pub.publish(marker_pose) + + +def left_franka_state_callback(msg): + """ + This callback function set `has_error` variable to True if the left arm is having an error. + :param msg: FrankaState msg data + :return: None + """ + global has_error, left_has_error + if msg.robot_mode == FrankaState.ROBOT_MODE_MOVE: + left_has_error = False + else: + left_has_error = True + has_error = left_has_error or right_has_error + + +def right_franka_state_callback(msg): + """ + This callback function set `has_error` variable to True if the right arm is having an error. + :param msg: FrankaState msg data + :return: None + """ + global has_error, right_has_error + if msg.robot_mode == FrankaState.ROBOT_MODE_MOVE: + right_has_error = False + else: + right_has_error = True + has_error = left_has_error or right_has_error + + +def reset_marker_pose_blocking(): + """ + This function resets the marker pose to current "middle pose" of left and right arm EEs. + :return: None + """ + + global marker_pose + marker_pose = rospy.wait_for_message( + "dual_arm_cartesian_impedance_example_controller/centering_frame", PoseStamped) + + +def process_feedback(feedback): + """ + This callback function clips the marker_pose inside a predefined box to prevent misuse of the + marker. + :param feedback: feedback data of interactive marker + :return: None + """ + global marker_pose + if feedback.event_type == InteractiveMarkerFeedback.POSE_UPDATE: + marker_pose.pose.position.x = feedback.pose.position.x + marker_pose.pose.position.y = feedback.pose.position.y + marker_pose.pose.position.z = feedback.pose.position.z + marker_pose.pose.orientation = feedback.pose.orientation + server.applyChanges() + + +if __name__ == "__main__": + rospy.init_node("target_pose_node") + + parser = argparse.ArgumentParser("dual_panda_interactive_marker.py") + parser.add_argument("--left_arm_id", + help="The id of the left arm.", + required=True) + parser.add_argument("--right_arm_id", + help="The id of the right arm.", + required=True) + parser.add_argument('args', nargs=argparse.REMAINDER) + args = parser.parse_args() + + # Arm IDs of left and right arms + left_arm_id = args.left_arm_id + right_arm_id = args.right_arm_id + + # Initialize subscribers for error states of the arms + left_state_sub = rospy.Subscriber(left_arm_id + "_state_controller/franka_states", + FrankaState, left_franka_state_callback) + + right_state_sub = rospy.Subscriber(right_arm_id + "_state_controller/franka_states", + FrankaState, right_franka_state_callback) + + # Set marker pose to be the current "middle pose" of both EEs + reset_marker_pose_blocking() + + # Initialize publisher for publishing desired centering pose + pose_pub = rospy.Publisher( + "dual_arm_cartesian_impedance_example_controller/centering_frame_target_pose", + PoseStamped, + queue_size=1) + + # Interactive marker settings + server = InteractiveMarkerServer("target_pose_marker") + int_marker = InteractiveMarker() + int_marker.header.frame_id = marker_pose.header.frame_id + int_marker.scale = 0.3 + int_marker.name = "centering_frame_pose" + int_marker.description = ("Target centering pose\n" + "BE CAREFUL! \n" + "If you move the target marker\n" + "both robots will follow it \n" + "as the center between the two\n" + "endeffectors. Be aware of\n" + "potential collisions!") + int_marker.pose = marker_pose.pose + + # insert a box + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 1 + control.orientation.y = 0 + control.orientation.z = 0 + control.name = "rotate_x" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 1 + control.orientation.y = 0 + control.orientation.z = 0 + control.name = "move_x" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 1 + control.orientation.z = 0 + control.name = "rotate_y" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 1 + control.orientation.z = 0 + control.name = "move_y" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 0 + control.orientation.z = 1 + control.name = "rotate_z" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 0 + control.orientation.z = 1 + control.name = "move_z" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 1 + control.orientation.y = 1 + control.orientation.z = 1 + control.name = "move_3D" + control.always_visible = True + control.markers.append(make_sphere()) + control.interaction_mode = InteractiveMarkerControl.MOVE_3D + int_marker.controls.append(control) + + server.insert(int_marker, process_feedback) + server.applyChanges() + + # main loop + while not rospy.is_shutdown(): + publish_target_pose() + if has_error: + reset_marker_pose_blocking() + publish_target_pose() + server.setPose("centering_frame_pose", marker_pose.pose) + server.applyChanges() + rospy.sleep(0.5) + rospy.sleep(0.1) diff --git a/fr3_impedance_controller_real/bak/scripts/interactive_marker.py b/fr3_impedance_controller_real/bak/scripts/interactive_marker.py new file mode 100755 index 0000000000000000000000000000000000000000..1893debeb98abc733fe20d07cf0a60a001400cba --- /dev/null +++ b/fr3_impedance_controller_real/bak/scripts/interactive_marker.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +import rospy +import tf.transformations +import numpy as np + +from interactive_markers.interactive_marker_server import \ + InteractiveMarkerServer, InteractiveMarkerFeedback +from visualization_msgs.msg import InteractiveMarker, \ + InteractiveMarkerControl +from geometry_msgs.msg import PoseStamped +from franka_msgs.msg import FrankaState + +marker_pose = PoseStamped() +pose_pub = None +# [[min_x, max_x], [min_y, max_y], [min_z, max_z]] +position_limits = [[-0.6, 0.6], [-0.6, 0.6], [0.05, 0.9]] + + +def publisher_callback(msg, link_name): + marker_pose.header.frame_id = link_name + marker_pose.header.stamp = rospy.Time(0) + pose_pub.publish(marker_pose) + + +def process_feedback(feedback): + if feedback.event_type == InteractiveMarkerFeedback.POSE_UPDATE: + marker_pose.pose.position.x = max([min([feedback.pose.position.x, + position_limits[0][1]]), + position_limits[0][0]]) + marker_pose.pose.position.y = max([min([feedback.pose.position.y, + position_limits[1][1]]), + position_limits[1][0]]) + marker_pose.pose.position.z = max([min([feedback.pose.position.z, + position_limits[2][1]]), + position_limits[2][0]]) + marker_pose.pose.orientation = feedback.pose.orientation + server.applyChanges() + + +def wait_for_initial_pose(): + msg = rospy.wait_for_message("franka_state_controller/franka_states", + FrankaState) # type: FrankaState + + initial_quaternion = \ + tf.transformations.quaternion_from_matrix( + np.transpose(np.reshape(msg.O_T_EE, + (4, 4)))) + initial_quaternion = initial_quaternion / \ + np.linalg.norm(initial_quaternion) + marker_pose.pose.orientation.x = initial_quaternion[0] + marker_pose.pose.orientation.y = initial_quaternion[1] + marker_pose.pose.orientation.z = initial_quaternion[2] + marker_pose.pose.orientation.w = initial_quaternion[3] + marker_pose.pose.position.x = msg.O_T_EE[12] + marker_pose.pose.position.y = msg.O_T_EE[13] + marker_pose.pose.position.z = msg.O_T_EE[14] + + +if __name__ == "__main__": + rospy.init_node("equilibrium_pose_node") + listener = tf.TransformListener() + link_name = rospy.get_param("~link_name") + + wait_for_initial_pose() + + pose_pub = rospy.Publisher( + "equilibrium_pose", PoseStamped, queue_size=10) + server = InteractiveMarkerServer("equilibrium_pose_marker") + int_marker = InteractiveMarker() + int_marker.header.frame_id = link_name + int_marker.scale = 0.3 + int_marker.name = "equilibrium_pose" + int_marker.description = ("Equilibrium Pose\nBE CAREFUL! " + "If you move the \nequilibrium " + "pose the robot will follow it\n" + "so be aware of potential collisions") + int_marker.pose = marker_pose.pose + # run pose publisher + rospy.Timer(rospy.Duration(0.005), + lambda msg: publisher_callback(msg, link_name)) + + # insert a box + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 1 + control.orientation.y = 0 + control.orientation.z = 0 + control.name = "rotate_x" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 1 + control.orientation.y = 0 + control.orientation.z = 0 + control.name = "move_x" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 1 + control.orientation.z = 0 + control.name = "rotate_y" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 1 + control.orientation.z = 0 + control.name = "move_y" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 0 + control.orientation.z = 1 + control.name = "rotate_z" + control.interaction_mode = InteractiveMarkerControl.ROTATE_AXIS + int_marker.controls.append(control) + control = InteractiveMarkerControl() + control.orientation.w = 1 + control.orientation.x = 0 + control.orientation.y = 0 + control.orientation.z = 1 + control.name = "move_z" + control.interaction_mode = InteractiveMarkerControl.MOVE_AXIS + int_marker.controls.append(control) + server.insert(int_marker, process_feedback) + + server.applyChanges() + + rospy.spin() diff --git a/fr3_impedance_controller_real/bak/scripts/move_to_start.py b/fr3_impedance_controller_real/bak/scripts/move_to_start.py new file mode 100755 index 0000000000000000000000000000000000000000..0e75e3dde5b1156647922d573d03ad40b5daacdc --- /dev/null +++ b/fr3_impedance_controller_real/bak/scripts/move_to_start.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +import sys +import rospy as ros + +from actionlib import SimpleActionClient +from sensor_msgs.msg import JointState +from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint +from control_msgs.msg import FollowJointTrajectoryAction, \ + FollowJointTrajectoryGoal, FollowJointTrajectoryResult + +ros.init_node('move_to_start') + +action = ros.resolve_name('~follow_joint_trajectory') +client = SimpleActionClient(action, FollowJointTrajectoryAction) +ros.loginfo("move_to_start: Waiting for '" + action + "' action to come up") +client.wait_for_server() + +param = ros.resolve_name('~joint_pose') +pose = ros.get_param(param, None) +if pose is None: + ros.logerr('move_to_start: Could not find required parameter "' + param + '"') + sys.exit(1) + +topic = ros.resolve_name('~joint_states') +ros.loginfo("move_to_start: Waiting for message on topic '" + topic + "'") +joint_state = ros.wait_for_message(topic, JointState) +initial_pose = dict(zip(joint_state.name, joint_state.position)) + +max_movement = max(abs(pose[joint] - initial_pose[joint]) for joint in pose) + +point = JointTrajectoryPoint() +point.time_from_start = ros.Duration.from_sec( + # Use either the time to move the furthest joint with 'max_dq' or 500ms, + # whatever is greater + max(max_movement / ros.get_param('~max_dq', 0.5), 0.5) +) +goal = FollowJointTrajectoryGoal() + +goal.trajectory.joint_names, point.positions = [list(x) for x in zip(*pose.items())] +point.velocities = [0] * len(pose) + +goal.trajectory.points.append(point) +goal.goal_time_tolerance = ros.Duration.from_sec(0.5) + +ros.loginfo('Sending trajectory Goal to move into initial config') +client.send_goal_and_wait(goal) + +result = client.get_result() +if result.error_code != FollowJointTrajectoryResult.SUCCESSFUL: + ros.logerr('move_to_start: Movement was not successful: ' + { + FollowJointTrajectoryResult.INVALID_GOAL: + """ + The joint pose you want to move to is invalid (e.g. unreachable, singularity...). + Is the 'joint_pose' reachable? + """, + + FollowJointTrajectoryResult.INVALID_JOINTS: + """ + The joint pose you specified is for different joints than the joint trajectory controller + is claiming. Does you 'joint_pose' include all 7 joints of the robot? + """, + + FollowJointTrajectoryResult.PATH_TOLERANCE_VIOLATED: + """ + During the motion the robot deviated from the planned path too much. Is something blocking + the robot? + """, + + FollowJointTrajectoryResult.GOAL_TOLERANCE_VIOLATED: + """ + After the motion the robot deviated from the desired goal pose too much. Probably the robot + didn't reach the joint_pose properly + """, + }[result.error_code]) + +else: + ros.loginfo('move_to_start: Successfully moved into start pose') diff --git a/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.cpp b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..680cb97212a10731376076ae3563e49c10b632f8 --- /dev/null +++ b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.cpp @@ -0,0 +1,214 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/spacenav_teleop_twist_controller.h> + +#include <array> +#include <cmath> +#include <memory> +#include <string> + +#include <actionlib/client/simple_action_client.h> +#include <franka_gripper/MoveAction.h> +#include <franka_gripper/StopAction.h> +#include <franka_gripper/franka_gripper.h> +#include <controller_interface/controller_base.h> +#include <hardware_interface/hardware_interface.h> +#include <hardware_interface/joint_command_interface.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +namespace franka_example_controllers { + +bool SpacenavTeleopTwistController::init(hardware_interface::RobotHW* robot_hardware, + ros::NodeHandle& node_handle) { + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) { + ROS_ERROR("SpacenavTeleopTwistController: Could not get parameter arm_id"); + return false; + } + + velocity_cartesian_interface_ = + robot_hardware->get<franka_hw::FrankaVelocityCartesianInterface>(); + if (velocity_cartesian_interface_ == nullptr) { + ROS_ERROR( + "SpacenavTeleopTwistController: Could not get Cartesian velocity interface from " + "hardware"); + return false; + } + try { + velocity_cartesian_handle_ = std::make_unique<franka_hw::FrankaCartesianVelocityHandle>( + velocity_cartesian_interface_->getHandle(arm_id + "_robot")); + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "SpacenavTeleopTwistController: Exception getting Cartesian handle: " << e.what()); + return false; + } + + auto state_interface = robot_hardware->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) { + ROS_ERROR("SpacenavTeleopTwistController: Could not get state interface from hardware"); + return false; + } + + if (!node_handle.getParam("linear_gain", linear_gain_)) { + ROS_ERROR("SpacenavTeleopTwistController: Could not get parameter linear_gain"); + return false; + } + ROS_INFO_STREAM("SpacenavTeleopTwistController: Using linear_gain " << linear_gain_); + if (!node_handle.getParam("angular_gain", angular_gain_)) { + ROS_ERROR("SpacenavTeleopTwistController: Could not get parameter angular_gain"); + return false; + } + ROS_INFO_STREAM("SpacenavTeleopTwistController: Using angular_gain " << angular_gain_); + + ac_move = new actionlib::SimpleActionClient<franka_gripper::MoveAction>("franka_gripper/move", false); + ac_stop = new actionlib::SimpleActionClient<franka_gripper::StopAction>("franka_gripper/stop", false); + ROS_INFO("Waiting for MoveAction server to start."); + ac_move->waitForServer(); + //Subscribing to relevant twist topic + twist_sub_ = node_handle.subscribe<geometry_msgs::Twist>("/spacenav/twist", 1, &SpacenavTeleopTwistController::twistCallback, this); + //Subscribing to joy topic for button information + joy_sub_ = node_handle.subscribe<sensor_msgs::Joy>("/spacenav/joy", 1, &SpacenavTeleopTwistController::joyCallback, this); + //initializing variables + jerk_limit = 75; + + /** + try { + auto state_handle = state_interface->getHandle(arm_id + "_robot"); + + std::array<double, 7> q_start = {{0, -M_PI_4, 0, -3 * M_PI_4, 0, M_PI_2, M_PI_4}}; + for (size_t i = 0; i < q_start.size(); i++) { + if (std::abs(state_handle.getRobotState().q_d[i] - q_start[i]) > 0.1) { + ROS_ERROR_STREAM( + "CartesianVelocityExampleController: Robot is not in the expected starting position " + "for running this example. Run `roslaunch franka_example_controllers " + "move_to_start.launch robot_ip:=<robot-ip> load_gripper:=<has-attached-gripper>` " + "first."); + return false; + } + } + } catch (const hardware_interface::HardwareInterfaceException& e) { + ROS_ERROR_STREAM( + "CartesianVelocityExampleController: Exception getting state handle: " << e.what()); + return false; + } + **/ + + return true; +} + +void SpacenavTeleopTwistController::starting(const ros::Time& /* time */) { + elapsed_time_ = ros::Duration(0.0); + std::array<double, 6> command = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; + std::array<double, 6> command_prev = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; + std::array<double, 6> accel = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; + std::array<double, 6> accel_prev = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}; + velocity_cartesian_handle_->setCommand(command); +} + +void SpacenavTeleopTwistController::update(const ros::Time& /* time */, + const ros::Duration& period) { + + double steptime = period.toSec(); + // ROS_INFO("Steptime: %f", steptime); + std::array<double, 6> command = {{twist_command.linear.x, + twist_command.linear.y, + twist_command.linear.z, + twist_command.angular.x, + twist_command.angular.y, + twist_command.angular.z}}; + std::array<double, 6> accel = {{(command[0]-command_prev[0])/steptime, + (command[1]-command_prev[1])/steptime, + (command[2]-command_prev[2])/steptime, + (command[3]-command_prev[3])/steptime, + (command[4]-command_prev[4])/steptime, + (command[5]-command_prev[5])/steptime}}; + std::array<double, 6> jerk = {{(accel[0]-accel_prev[0])/steptime, + (accel[1]-accel_prev[1])/steptime, + (accel[2]-accel_prev[2])/steptime, + (accel[3]-accel_prev[3])/steptime, + (accel[4]-accel_prev[4])/steptime, + (accel[5]-accel_prev[5])/steptime}}; + + + //scale down acc and then command to be + for (int i = 0; i < 6; i++) + { + if (jerk[i]>= jerk_limit) + { + accel[i] = (jerk_limit * steptime) + accel_prev[i]; + command[i] = (accel[i] * steptime) + command_prev[i]; + } + else if (jerk[i]<= -jerk_limit) + { + accel[i] = (-jerk_limit * steptime) + accel_prev[i]; + command[i] = (accel[i] * steptime) + command_prev[i]; + } + } + + command_prev = {{command[0], + command[1], + command[2], + command[3], + command[4], + command[5]}}; + accel_prev = {{accel[0], + accel[1], + accel[2], + accel[3], + accel[4], + accel[5]}}; + velocity_cartesian_handle_->setCommand(command); + //Gripper logic + int idx = -1; + int *foo = std::find(std::begin(button_command), std::end(button_command), 1); + actionlib::SimpleClientGoalState state = ac_move->getState(); + //ROS_INFO("Current state: %s", state.toString().c_str()); + // When the element is not found, std::find returns the end of the range + if (foo != std::end(button_command)) { + idx = std::distance(std::begin(button_command), foo); + if (state.toString() != "ACTIVE") { + if (idx == 0) { + move_goal.width = 0.1; + move_goal.speed = 0.01; + ac_move->sendGoal(move_goal); + } + else if (idx == 1) { + move_goal.width = 0.0; + move_goal.speed = 0.01; + ac_move->sendGoal(move_goal); + } + } + } else { + if (state.toString() == "ACTIVE") { + ac_move->cancelAllGoals(); + ac_stop->sendGoal(stop_goal); + } + } + +} + +void SpacenavTeleopTwistController::stopping(const ros::Time& /*time*/) { + // WARNING: DO NOT SEND ZERO VELOCITIES HERE AS IN CASE OF ABORTING DURING MOTION + // A JUMP TO ZERO WILL BE COMMANDED PUTTING HIGH LOADS ON THE ROBOT. LET THE DEFAULT + // BUILT-IN STOPPING BEHAVIOR SLOW DOWN THE ROBOT. +} + +void SpacenavTeleopTwistController::twistCallback(const geometry_msgs::TwistConstPtr& msg) { + twist_command.linear.x = linear_gain_ * msg->linear.x; + twist_command.linear.y = linear_gain_ * msg->linear.y; + twist_command.linear.z = linear_gain_ * msg->linear.z; + twist_command.angular.x = angular_gain_ * msg->angular.x; + twist_command.angular.y = angular_gain_ * msg->angular.y; + twist_command.angular.z = angular_gain_ * msg->angular.z; +} + +void SpacenavTeleopTwistController::joyCallback(const sensor_msgs::JoyConstPtr& msg) { + button_command[0] = msg->buttons[0]; + button_command[1] = msg->buttons[1]; +} + +}// namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::SpacenavTeleopTwistController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.h b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..97beea742510a21d1f81fc4fd7c7fc7e8b42fec1 --- /dev/null +++ b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.h @@ -0,0 +1,52 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <string> + +#include <controller_interface/multi_interface_controller.h> +#include <franka_hw/franka_cartesian_command_interface.h> +#include <franka_hw/franka_state_interface.h> +#include <actionlib/client/simple_action_client.h> +#include <franka_gripper/MoveAction.h> +#include <franka_gripper/StopAction.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> +#include <geometry_msgs/Twist.h> +#include <sensor_msgs/Joy.h> + +namespace franka_example_controllers { + +class SpacenavTeleopTwistController : public controller_interface::MultiInterfaceController< + franka_hw::FrankaVelocityCartesianInterface, + franka_hw::FrankaStateInterface> { + public: + bool init(hardware_interface::RobotHW* robot_hardware, ros::NodeHandle& node_handle) override; + void update(const ros::Time&, const ros::Duration& period) override; + void starting(const ros::Time&) override; + void stopping(const ros::Time&) override; + + private: + franka_hw::FrankaVelocityCartesianInterface* velocity_cartesian_interface_; + std::unique_ptr<franka_hw::FrankaCartesianVelocityHandle> velocity_cartesian_handle_; + ros::Duration elapsed_time_; + ros::Subscriber twist_sub_; + ros::Subscriber joy_sub_; + actionlib::SimpleActionClient<franka_gripper::MoveAction> *ac_move; + actionlib::SimpleActionClient<franka_gripper::StopAction> *ac_stop; + double linear_gain_; + double angular_gain_; + void twistCallback(const geometry_msgs::TwistConstPtr& msg); + void joyCallback(const sensor_msgs::JoyConstPtr& msg); + geometry_msgs::Twist twist_command; + std::array<int, 2> button_command; + std::array<double, 6> command_prev; + std::array<double, 6> accel_prev; + double jerk_limit; + franka_gripper::MoveGoal move_goal; + franka_gripper::StopGoal stop_goal; +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.launch b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..73815da630499d86d61dc12f3feb5758b29662d7 --- /dev/null +++ b/fr3_impedance_controller_real/bak/spacenav_teleop_twist_controller.launch @@ -0,0 +1,12 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="arm_id" default="$(arg robot)" /> + <arg name="linear_gain" default="0.01" /> + <arg name="angular_gain" default="0.01" /> + <include file="$(find spacenav_node)/launch/classic.launch" pass_all_args="true"/> + <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="spacenav_teleop_twist_controller"/> + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/robot.rviz"/> +</launch> diff --git a/fr3_impedance_controller_real/bak/teleop_gripper.launch b/fr3_impedance_controller_real/bak/teleop_gripper.launch new file mode 100644 index 0000000000000000000000000000000000000000..ddb758977c7180aafe6a165f6f159a0ee05d33e8 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_gripper.launch @@ -0,0 +1,35 @@ +<?xml version="1.0" ?> +<launch> + <arg name="robot_id" /> + <arg name="leader_ip" /> + <arg name="follower_ip" /> + <arg name="leader_id" default="panda_1" /> + <arg name="follower_id" default="panda_2" /> + <arg name="gripper_homed" default="false" /> + + <group ns="$(arg leader_id)"> + <include file="$(find franka_gripper)/launch/franka_gripper.launch" > + <arg name="robot_ip" value="$(arg leader_ip)" /> + <arg name="stop_at_shutdown" value="true" /> + <arg name="arm_id" value="$(arg leader_id)" /> + </include> + </group> + + <group ns="$(arg follower_id)"> + <include file="$(find franka_gripper)/launch/franka_gripper.launch" > + <arg name="robot_ip" value="$(arg follower_ip)" /> + <arg name="stop_at_shutdown" value="true" /> + <arg name="arm_id" value="$(arg follower_id)" /> + </include> + </group> + + <node name="teleop_gripper_node" pkg="franka_example_controllers" type="teleop_gripper_node" respawn="false" output="screen" > + <rosparam param="gripper_homed" subst_value="true">$(arg gripper_homed)</rosparam> + <remap from="~leader/joint_states" to="$(arg leader_id)/franka_gripper/joint_states" /> + <remap from="leader/homing" to="$(arg leader_id)/franka_gripper/homing" /> + <remap from="follower/homing" to="$(arg follower_id)/franka_gripper/homing" /> + <remap from="follower/grasp" to="$(arg follower_id)/franka_gripper/grasp" /> + <remap from="follower/move" to="$(arg follower_id)/franka_gripper/move" /> + <remap from="follower/stop" to="$(arg follower_id)/franka_gripper/stop" /> + </node> +</launch> diff --git a/fr3_impedance_controller_real/bak/teleop_gripper_node.cpp b/fr3_impedance_controller_real/bak/teleop_gripper_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..231805ff3185b84a3e9e038feaf9d607cd15f229 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_gripper_node.cpp @@ -0,0 +1,190 @@ +// Copyright (c) 2020 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka/gripper.h> +#include <franka_example_controllers/teleop_gripper_paramConfig.h> +#include <franka_gripper/GraspAction.h> +#include <franka_gripper/HomingAction.h> +#include <franka_gripper/MoveAction.h> +#include <franka_gripper/StopAction.h> + +#include <actionlib/client/simple_action_client.h> +#include <dynamic_reconfigure/server.h> +#include <ros/init.h> +#include <ros/node_handle.h> +#include <sensor_msgs/JointState.h> + +#include <functional> +#include <memory> +#include <mutex> + +using franka_gripper::GraspAction; +using franka_gripper::HomingAction; +using franka_gripper::MoveAction; +using franka_gripper::StopAction; +using GraspClient = actionlib::SimpleActionClient<GraspAction>; +using HomingClient = actionlib::SimpleActionClient<HomingAction>; +using MoveClient = actionlib::SimpleActionClient<MoveAction>; +using StopClient = actionlib::SimpleActionClient<StopAction>; + +/** + * Client class for teleoperating a follower gripper from a leader gripper. + * By closing the leader gripper manually, exceeding a defined width threshold, a ROS + * action is called and the follower gripper will grasp an object with a configurable force. + * When opening the leader gripper, the follower gripper will also open. + */ +class TeleopGripperClient { + public: + TeleopGripperClient() + : leader_homing_client_("leader/homing", true), + follower_homing_client_("follower/homing", true), + grasp_client_("follower/grasp", true), + move_client_("follower/move", true), + stop_client_("follower/stop", true){}; + + bool init(const std::shared_ptr<ros::NodeHandle>& pnh) { + grasping_ = false; + gripper_homed_ = false; + if (!pnh->getParam("gripper_homed", gripper_homed_)) { + ROS_INFO_STREAM( + "teleop_gripper_node: Could not read parameter gripper_homed. " + "Defaulting to " + << std::boolalpha << gripper_homed_); + } + + // Init for dynamic reconfigure + dynamic_reconfigure_teleop_gripper_param_node_ = + ros::NodeHandle("dyn_reconf_teleop_gripper_param_node"); + dynamic_server_teleop_gripper_param_ = std::make_unique< + dynamic_reconfigure::Server<franka_example_controllers::teleop_gripper_paramConfig>>( + dynamic_reconfigure_teleop_gripper_param_node_); + dynamic_server_teleop_gripper_param_->setCallback( + boost::bind(&TeleopGripperClient::teleopGripperParamCallback, this, _1, _2)); + + bool homing_success(false); + if (!gripper_homed_) { + ROS_INFO("teleop_gripper_node: Homing Gripper."); + homing_success = homingGripper(); + } + + if (gripper_homed_ || homing_success) { + // Start action servers and subscriber for gripper + ros::Duration timeout(2.0); + if (grasp_client_.waitForServer(timeout) && move_client_.waitForServer(timeout) && + stop_client_.waitForServer(timeout)) { + leader_sub_ = pnh->subscribe("leader/joint_states", 1, + &TeleopGripperClient::subscriberCallback, this); + } else { + ROS_ERROR( + "teleop_gripper_node: Action Server could not be started. Shutting " + "down node."); + return false; + } + } else { + return false; + } + return true; + }; + + private: + double max_width_{0.07}; // Default value. It will be reset when gripper is homed [m] + bool grasping_; + bool gripper_homed_; + + double grasp_force_; // [N] + double grasp_epsilon_inner_{0.001}; // [m] + double grasp_epsilon_outer_scaling_{100}; + double move_speed_; // [m/s] + + double start_pos_grasping_{0.5}; // Threshold position of leader gripper where to start grasping. + double start_pos_opening_{0.6}; // Threshold position of leader gripper where to open. + + HomingClient follower_homing_client_; + HomingClient leader_homing_client_; + GraspClient grasp_client_; + MoveClient move_client_; + StopClient stop_client_; + + std::mutex subscriber_mutex_; + ros::Subscriber leader_sub_; + + std::mutex dynamic_reconfigure_mutex_; + ros::NodeHandle dynamic_reconfigure_teleop_gripper_param_node_; + std::unique_ptr< + dynamic_reconfigure::Server<franka_example_controllers::teleop_gripper_paramConfig>> + dynamic_server_teleop_gripper_param_; + + void teleopGripperParamCallback( + const franka_example_controllers::teleop_gripper_paramConfig& config, + uint32_t /*level*/) { + if (dynamic_reconfigure_mutex_.try_lock()) { + grasp_force_ = config.grasp_force; + move_speed_ = config.move_speed; + ROS_INFO_STREAM("Dynamic Reconfigure: Gripper params set: grasp_force = " + << grasp_force_ << " N ; move_speed = " << move_speed_ << " m/s"); + } + dynamic_reconfigure_mutex_.unlock(); + }; + + bool homingGripper() { + if (follower_homing_client_.waitForServer(ros::Duration(2.0)) && + leader_homing_client_.waitForServer(ros::Duration(2.0))) { + leader_homing_client_.sendGoal(franka_gripper::HomingGoal()); + follower_homing_client_.sendGoal(franka_gripper::HomingGoal()); + + if (leader_homing_client_.waitForResult(ros::Duration(10.0)) && + follower_homing_client_.waitForResult(ros::Duration(10.0))) { + return true; + } + } + ROS_ERROR("teleop_gripper_node: HomingAction has timed out."); + return false; + } + + void subscriberCallback(const sensor_msgs::JointState& msg) { + std::lock_guard<std::mutex> _(subscriber_mutex_); + if (!gripper_homed_) { + // If gripper had to be homed, reset max_width_. + max_width_ = 2 * msg.position[0]; + gripper_homed_ = true; + } + double gripper_width = 2 * msg.position[0]; + if (gripper_width < start_pos_grasping_ * max_width_ && !grasping_) { + // Grasp object + franka_gripper::GraspGoal grasp_goal; + grasp_goal.force = grasp_force_; + grasp_goal.speed = move_speed_; + grasp_goal.epsilon.inner = grasp_epsilon_inner_; + grasp_goal.epsilon.outer = grasp_epsilon_outer_scaling_ * max_width_; + + grasp_client_.sendGoal(grasp_goal); + if (grasp_client_.waitForResult(ros::Duration(5.0))) { + grasping_ = true; + } else { + ROS_INFO("teleop_gripper_node: GraspAction was not successful."); + stop_client_.sendGoal(franka_gripper::StopGoal()); + } + } else if (gripper_width > start_pos_opening_ * max_width_ && grasping_) { + // Open gripper + franka_gripper::MoveGoal move_goal; + move_goal.speed = move_speed_; + move_goal.width = max_width_; + move_client_.sendGoal(move_goal); + if (move_client_.waitForResult(ros::Duration(5.0))) { + grasping_ = false; + } else { + ROS_ERROR("teleop_gripper_node: MoveAction was not successful."); + stop_client_.sendGoal(franka_gripper::StopGoal()); + } + } + } +}; + +int main(int argc, char** argv) { + ros::init(argc, argv, "teleop_gripper_node"); + auto pnh = std::make_shared<ros::NodeHandle>("~"); + TeleopGripperClient teleop_gripper_client; + if (teleop_gripper_client.init(pnh)) { + ros::spin(); + } + return 0; +} diff --git a/fr3_impedance_controller_real/bak/teleop_gripper_param.cfg b/fr3_impedance_controller_real/bak/teleop_gripper_param.cfg new file mode 100755 index 0000000000000000000000000000000000000000..5f0d9e14310d5012f5655c2e2459b1a1c08218d0 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_gripper_param.cfg @@ -0,0 +1,17 @@ +#!/usr/bin/env python +PACKAGE = "franka_example_controllers" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +gripper_param = gen.add_group("GripperParameter", type="apply") + +gripper_param.add("grasp_force", double_t, 0, + "Grasping force to be applied on an object. [N]", 40.0, 1.0, + 60.0) +gripper_param.add("move_speed", double_t, 0, + "Speed of the follower gripper when opening [m/s]", 0.3, + 0.01, 0.4) + +exit(gen.generate(PACKAGE, "teleop_gripper_param", "teleop_gripper_param")) diff --git a/fr3_impedance_controller_real/bak/teleop_joint_pd_example_control_node.yaml b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_control_node.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5c5a66a4221669259527eb99b5daa0a4f34b17b4 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_control_node.yaml @@ -0,0 +1,69 @@ +robot_hardware: + - leader + - follower + +leader: + type: franka_hw/FrankaCombinableHW + arm_id: leader + joint_names: + - leader_joint1 + - leader_joint2 + - leader_joint3 + - leader_joint4 + - leader_joint5 + - leader_joint6 + - leader_joint7 + # Configure the threshold angle for printing joint limit warnings. + joint_limit_warning_threshold: 0.1 # [rad] + # Activate rate limiter? [true|false] + rate_limiting: true + # Cutoff frequency of the low-pass filter. Set to >= 1000 to deactivate. + cutoff_frequency: 1000 + # Internal controller for motion generators [joint_impedance|cartesian_impedance] + internal_controller: joint_impedance + # Used to decide whether to enforce realtime mode [enforce|ignore] + realtime_config: enforce + # Configure collision behavior reflexes. + # The upper torque and upper force thresholds are set to higher values compared to the default ones. + collision_config: + lower_torque_thresholds_acceleration: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + upper_torque_thresholds_acceleration: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + lower_torque_thresholds_nominal: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + upper_torque_thresholds_nominal: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + lower_force_thresholds_acceleration: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + upper_force_thresholds_acceleration: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + lower_force_thresholds_nominal: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + upper_force_thresholds_nominal: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + +follower: + type: franka_hw/FrankaCombinableHW + arm_id: follower + joint_names: + - follower_joint1 + - follower_joint2 + - follower_joint3 + - follower_joint4 + - follower_joint5 + - follower_joint6 + - follower_joint7 + # Configure the threshold angle for printing joint limit warnings. + joint_limit_warning_threshold: 0.1 # [rad] + # Activate rate limiter? [true|false] + rate_limiting: true + # Cutoff frequency of the low-pass filter. Set to >= 1000 to deactivate. + cutoff_frequency: 1000 + # Internal controller for motion generators [joint_impedance|cartesian_impedance] + internal_controller: joint_impedance + # Used to decide whether to enforce realtime mode [enforce|ignore] + realtime_config: enforce + # Configure collision behavior reflexes. + # The upper torque and upper force thresholds are set to higher values compared to the default ones. + collision_config: + lower_torque_thresholds_acceleration: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + upper_torque_thresholds_acceleration: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + lower_torque_thresholds_nominal: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + upper_torque_thresholds_nominal: [25.0, 25.0, 23.0, 23.0, 20.0, 17.5, 15.0] # [Nm] + lower_force_thresholds_acceleration: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + upper_force_thresholds_acceleration: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + lower_force_thresholds_nominal: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] + upper_force_thresholds_nominal: [40.0, 40.0, 40.0, 40.0, 40.0, 40.0] # [N, N, N, Nm, Nm, Nm] diff --git a/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.cpp b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..027202f9534456dffbccfa261da4e48ba38ea73a --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.cpp @@ -0,0 +1,537 @@ +// Copyright (c) 2020 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/joint_wall.h> +#include <franka_example_controllers/teleop_joint_pd_example_controller.h> + +#include <hardware_interface/hardware_interface.h> +#include <joint_limits_interface/joint_limits_urdf.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> +#include <urdf/model.h> + +#include <Eigen/Dense> +#include <algorithm> +#include <cmath> +#include <functional> +#include <string> +#include <vector> + +using Vector7d = Eigen::Matrix<double, 7, 1>; + +const std::string kControllerName = "TeleopJointPDExampleController"; + +namespace franka_example_controllers { + +bool TeleopJointPDExampleController::init(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle) { + std::string leader_arm_id; + std::string follower_arm_id; + + std::vector<std::string> leader_joint_names; + std::vector<std::string> follower_joint_names; + + try { + k_d_leader_lower_ = get7dParam("leader/d_gains_lower", node_handle); + k_d_leader_upper_ = get7dParam("leader/d_gains_upper", node_handle); + dq_max_leader_lower_ = get7dParam("leader/dq_max_lower", node_handle); + dq_max_leader_upper_ = get7dParam("leader/dq_max_upper", node_handle); + + k_p_follower_ = get7dParam("follower/p_gains", node_handle); + k_d_follower_ = get7dParam("follower/d_gains", node_handle); + k_dq_ = get7dParam("follower/drift_comp_gains", node_handle); + dq_max_lower_ = get7dParam("follower/dq_max_lower", node_handle); + dq_max_upper_ = get7dParam("follower/dq_max_upper", node_handle); + ddq_max_lower_ = get7dParam("follower/ddq_max_lower", node_handle); + ddq_max_upper_ = get7dParam("follower/ddq_max_upper", node_handle); + + leader_data_.contact_force_threshold = + get1dParam<double>("leader/contact_force_threshold", node_handle); + follower_data_.contact_force_threshold = + get1dParam<double>("follower/contact_force_threshold", node_handle); + + leader_arm_id = get1dParam<std::string>("leader/arm_id", node_handle); + follower_arm_id = get1dParam<std::string>("follower/arm_id", node_handle); + + leader_joint_names = getJointParams<std::string>("leader/joint_names", node_handle); + follower_joint_names = getJointParams<std::string>("follower/joint_names", node_handle); + + if (!node_handle.getParam("debug", debug_)) { + ROS_INFO_STREAM_NAMED(kControllerName, "Could not find parameter debug. Defaulting to " + << std::boolalpha << debug_); + } + + // Init for each arm + initArm(robot_hw, node_handle, leader_data_, leader_arm_id, leader_joint_names); + initArm(robot_hw, node_handle, follower_data_, follower_arm_id, follower_joint_names); + } catch (const std::invalid_argument& ex) { + ROS_ERROR_NAMED(kControllerName, "%s", ex.what()); + return false; + } + + if (debug_) { + // Init for dynamic reconfigure + dynamic_reconfigure_teleop_param_node_ = ros::NodeHandle("dyn_reconf_teleop_param_node"); + dynamic_server_teleop_param_ = std::make_unique< + dynamic_reconfigure::Server<franka_example_controllers::teleop_paramConfig>>( + dynamic_reconfigure_teleop_param_node_); + dynamic_server_teleop_param_->setCallback( + boost::bind(&TeleopJointPDExampleController::teleopParamCallback, this, _1, _2)); + + // Init for publishers + auto init_publisher = [&node_handle](auto& publisher, const auto& topic) { + publisher.init(node_handle, topic, 1); + publisher.lock(); + publisher.msg_.name.resize(7); + publisher.msg_.position.resize(7); + publisher.msg_.velocity.resize(7); + publisher.msg_.effort.resize(7); + publisher.unlock(); + }; + + init_publisher(leader_target_pub_, "leader_target"); + init_publisher(follower_target_pub_, "follower_target"); + leader_contact_pub_.init(node_handle, "leader_contact", 1); + follower_contact_pub_.init(node_handle, "follower_contact", 1); + marker_pub_.init(node_handle, "marker_labels", 1, true); + + auto get_marker = [](const std::string& arm_id, int32_t id, const std::string& text) { + visualization_msgs::Marker marker; + marker.header.frame_id = arm_id + "_link0"; + marker.header.stamp = ros::Time::now(); + marker.ns = "basic_shapes"; + marker.id = id; + marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING; + marker.action = visualization_msgs::Marker::ADD; + + marker.pose.position.x = 0.0; + marker.pose.position.y = 0.0; + marker.pose.position.z = 1.0; + marker.pose.orientation.x = 0.0; + marker.pose.orientation.y = 0.0; + marker.pose.orientation.z = 0.0; + marker.pose.orientation.w = 1.0; + + marker.text = text; + + marker.scale.x = 0.3; + marker.scale.y = 0.3; + marker.scale.z = 0.1; + + marker.color.r = 0.0f; + marker.color.g = 1.0f; + marker.color.b = 0.0f; + marker.color.a = 1.0; + return marker; + }; + + { + std::lock_guard<realtime_tools::RealtimePublisher<visualization_msgs::MarkerArray>> lock( + marker_pub_); + marker_pub_.msg_.markers.push_back(get_marker(leader_arm_id, 1, "leader")); + marker_pub_.msg_.markers.push_back(get_marker(follower_arm_id, 2, "follower")); + } + publishMarkers(); + } + + return true; +} + +void TeleopJointPDExampleController::initArm(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle, + FrankaDataContainer& arm_data, + const std::string& arm_id, + const std::vector<std::string>& joint_names) { + auto* effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); + if (not effort_joint_interface) { + throw std::invalid_argument(kControllerName + + ": Error getting effort joint interface from hardware of " + + arm_id + "."); + } + + arm_data.joint_handles.clear(); + for (const auto& name : joint_names) { + try { + arm_data.joint_handles.push_back(effort_joint_interface->getHandle(name)); + } catch (const hardware_interface::HardwareInterfaceException& e) { + throw std::invalid_argument(kControllerName + + ": Exception getting joint handle: " + std::string(e.what())); + } + } + + // Get state interface. + auto* state_interface = robot_hw->get<franka_hw::FrankaStateInterface>(); + if (not state_interface) { + throw std::invalid_argument(kControllerName + ": Error getting state interface from hardware."); + } + + try { + arm_data.state_handle = std::make_unique<franka_hw::FrankaStateHandle>( + state_interface->getHandle(arm_id + "_robot")); + } catch (hardware_interface::HardwareInterfaceException& ex) { + throw std::invalid_argument( + kControllerName + + ": Exception getting state handle from interface: " + std::string(ex.what())); + } + + // Setup joint walls + // Virtual joint position wall parameters + const std::array<double, 7> kPDZoneWidth = {{0.12, 0.09, 0.09, 0.09, 0.0349, 0.0349, 0.0349}}; + const std::array<double, 7> kDZoneWidth = {{0.12, 0.09, 0.09, 0.09, 0.0349, 0.0349, 0.0349}}; + const std::array<double, 7> kPDZoneStiffness = { + {2000.0, 2000.0, 1000.0, 1000.0, 500.0, 200.0, 200.0}}; + const std::array<double, 7> kPDZoneDamping = {{30.0, 30.0, 30.0, 10.0, 5.0, 5.0, 5.0}}; + const std::array<double, 7> kDZoneDamping = {{30.0, 30.0, 30.0, 10.0, 5.0, 5.0, 5.0}}; + + std::array<double, 7> upper_joint_soft_limit; + std::array<double, 7> lower_joint_soft_limit; + getJointLimits(node_handle, joint_names, upper_joint_soft_limit, lower_joint_soft_limit); + + arm_data.virtual_joint_wall = std::make_unique<JointWallContainer<7>>( + upper_joint_soft_limit, lower_joint_soft_limit, kPDZoneWidth, kDZoneWidth, kPDZoneStiffness, + kPDZoneDamping, kDZoneDamping); +} + +void TeleopJointPDExampleController::starting(const ros::Time& /*time*/) { + // Reset joint walls to start from the current q, dq + leader_data_.virtual_joint_wall->reset(); + follower_data_.virtual_joint_wall->reset(); + + // Reset stored states to the current states. + franka::RobotState follower_robot_state = follower_data_.state_handle->getRobotState(); + q_target_last_ = Eigen::Map<Vector7d>(follower_robot_state.q.data()); + dq_target_last_.setZero(); + leader_data_.tau_target_last.setZero(); + follower_data_.tau_target_last.setZero(); + + // Store alignment position from leader + franka::RobotState leader_robot_state = leader_data_.state_handle->getRobotState(); + init_leader_q_ = Eigen::Map<Vector7d>(leader_robot_state.q.data()); + current_state_ = TeleopStateMachine::ALIGN; + if (debug_) { + publishMarkers(); + } +} + +void TeleopJointPDExampleController::update(const ros::Time& /*time*/, + const ros::Duration& period) { + franka::RobotState leader_robot_state = leader_data_.state_handle->getRobotState(); + franka::RobotState follower_robot_state = follower_data_.state_handle->getRobotState(); + leader_data_.q = Eigen::Map<Vector7d>(leader_robot_state.q.data()); + leader_data_.dq = Eigen::Map<Vector7d>(leader_robot_state.dq.data()); + follower_data_.q = Eigen::Map<Vector7d>(follower_robot_state.q.data()); + follower_data_.dq = Eigen::Map<Vector7d>(follower_robot_state.dq.data()); + + if (current_state_ == TeleopStateMachine::ALIGN) { + // Check coefficient-wise if the two robots are aligned + const auto kNorm = (leader_data_.q - follower_data_.q).cwiseAbs().array(); + if ((kNorm < kAlignmentTolerance_).all()) { + current_state_ = TeleopStateMachine::TRACK; + ROS_INFO_STREAM_NAMED(kControllerName, "Leader and follower are aligned"); + } + } + + // Determine contact scaling factor depending on the external cartesian forces applied on the + // endeffector. + Vector6d leader_f_ext_hat = Eigen::Map<Vector6d>(leader_robot_state.K_F_ext_hat_K.data()); + leader_data_.f_ext_norm = leader_f_ext_hat.head(3).norm(); + leader_data_.contact = + rampParameter(leader_data_.f_ext_norm, 1.0, 0.0, leader_data_.contact_force_threshold, + leader_data_.contact_ramp_increase); + + Vector6d follower_f_ext_hat = Eigen::Map<Vector6d>(follower_robot_state.K_F_ext_hat_K.data()); + follower_data_.f_ext_norm = follower_f_ext_hat.head(3).norm(); + follower_data_.contact = + rampParameter(follower_data_.f_ext_norm, 1.0, 0.0, follower_data_.contact_force_threshold, + follower_data_.contact_ramp_increase); + + // Determine max velocities and accelerations of follower arm depending on tracking errors to + // avoid jumps and high velocities when starting example. + Vector7d q_deviation = (q_target_last_ - leader_data_.q).cwiseAbs(); + Vector7d dq_max; + Vector7d ddq_max; + + if (current_state_ == TeleopStateMachine::ALIGN) { + dq_max = dq_max_align_; + ddq_max = ddq_max_align_; + prev_alignment_error_ = alignment_error_; + alignment_error_ = (init_leader_q_ - follower_data_.q); + Vector7d dalignment_error = (alignment_error_ - prev_alignment_error_) / period.toSec(); + + dq_unsaturated_ = k_p_follower_align_.asDiagonal() * alignment_error_ + + k_d_follower_align_.asDiagonal() * dalignment_error; + } else { + for (size_t i = 0; i < 7; ++i) { + dq_max[i] = rampParameter(q_deviation[i], dq_max_lower_[i], dq_max_upper_[i], + velocity_ramp_shift_, velocity_ramp_increase_); + ddq_max[i] = rampParameter(q_deviation[i], ddq_max_lower_[i], ddq_max_upper_[i], + velocity_ramp_shift_, velocity_ramp_increase_); + } + dq_unsaturated_ = k_dq_.asDiagonal() * (leader_data_.q - q_target_last_) + leader_data_.dq; + } + + // Calculate target postions and velocities for follower arm + dq_target_ = saturateAndLimit(dq_unsaturated_, dq_target_last_, dq_max, ddq_max, period.toSec()); + dq_target_last_ = dq_target_; + q_target_ = q_target_last_ + (dq_target_ * period.toSec()); + q_target_last_ = q_target_; + + if (!leader_robot_state.current_errors && !follower_robot_state.current_errors) { + if (current_state_ == TeleopStateMachine::ALIGN) { + // Compute P control for the leader arm to stay in position. + leader_data_.tau_target = k_p_follower_.asDiagonal() * (init_leader_q_ - leader_data_.q); + } else { + // Compute force-feedback for the leader arm to render the haptic interaction of the follower + // robot. Add a slight damping to reduce vibrations. + // The force feedback is applied when the external forces on the follower arm exceed a + // threshold. While the leader arm is unguided (not in contact), the force-feedback is + // reduced. When the leader robot exceeds the soft limit velocities dq_max_leader_lower + // damping is increased gradually until it saturates when reaching dq_max_leader_upper to + // maximum damping. + + Vector7d follower_tau_ext_hat = + Eigen::Map<Vector7d>(follower_robot_state.tau_ext_hat_filtered.data()); + Vector7d leader_damping_torque = + leader_damping_scaling_ * leaderDamping(leader_data_.dq).asDiagonal() * leader_data_.dq; + Vector7d leader_force_feedback = + follower_data_.contact * + (force_feedback_idle_ + + leader_data_.contact * (force_feedback_guiding_ - force_feedback_idle_)) * + (-follower_tau_ext_hat); + + leader_data_.tau_target = leader_force_feedback - leader_damping_torque; + } + + // Compute PD control for the follower arm to track the leader's motions. + follower_data_.tau_target = + follower_stiffness_scaling_ * k_p_follower_.asDiagonal() * (q_target_ - follower_data_.q) + + sqrt(follower_stiffness_scaling_) * k_d_follower_.asDiagonal() * + (dq_target_ - follower_data_.dq); + } else { + // Control target torques to zero if any arm is in error state. + leader_data_.tau_target = decrease_factor_ * leader_data_.tau_target_last; + follower_data_.tau_target = decrease_factor_ * follower_data_.tau_target_last; + } + + // Add torques from joint walls to the torque commands. + auto to_eigen = [](const std::array<double, 7>& data) { return Vector7d(data.data()); }; + auto from_eigen = [](const Vector7d& data) { + return std::array<double, 7>{data(0), data(1), data(2), data(3), data(4), data(5), data(6)}; + }; + std::array<double, 7> virtual_wall_tau_leader = leader_data_.virtual_joint_wall->computeTorque( + from_eigen(leader_data_.q), from_eigen(leader_data_.dq)); + + std::array<double, 7> virtual_wall_tau_follower = + follower_data_.virtual_joint_wall->computeTorque(from_eigen(follower_data_.q), + from_eigen(follower_data_.dq)); + + leader_data_.tau_target += to_eigen(virtual_wall_tau_leader); + follower_data_.tau_target += to_eigen(virtual_wall_tau_follower); + + // Store torques for next time step + leader_data_.tau_target_last = leader_data_.tau_target; + follower_data_.tau_target_last = follower_data_.tau_target; + + updateArm(leader_data_); + updateArm(follower_data_); + + if (debug_ && publish_rate_()) { + publishLeaderTarget(); + publishFollowerTarget(); + publishLeaderContact(); + publishFollowerContact(); + } +} + +void TeleopJointPDExampleController::updateArm(FrankaDataContainer& arm_data) { + for (size_t i = 0; i < 7; ++i) { + arm_data.joint_handles[i].setCommand(arm_data.tau_target[i]); + } +} + +Eigen::Matrix<double, 7, 1> TeleopJointPDExampleController::saturateAndLimit(const Vector7d& x_calc, + const Vector7d& x_last, + const Vector7d& x_max, + const Vector7d& dx_max, + const double delta_t) { + Vector7d x_limited; + for (size_t i = 0; i < 7; i++) { + double delta_x_max = dx_max[i] * delta_t; + double diff = x_calc[i] - x_last[i]; + double x_saturated = x_last[i] + std::max(std::min(diff, delta_x_max), -delta_x_max); + x_limited[i] = std::max(std::min(x_saturated, x_max[i]), -x_max[i]); + } + return x_limited; +} + +double TeleopJointPDExampleController::rampParameter(const double x, + const double neg_x_asymptote, + const double pos_x_asymptote, + const double shift_along_x, + const double increase_factor) { + double ramp = + 0.5 * (pos_x_asymptote + neg_x_asymptote - + (pos_x_asymptote - neg_x_asymptote) * tanh(increase_factor * (x - shift_along_x))); + return ramp; +} + +void TeleopJointPDExampleController::teleopParamCallback( + franka_example_controllers::teleop_paramConfig& config, + uint32_t /*level*/) { + if (dynamic_reconfigure_mutex_.try_lock()) { + leader_damping_scaling_ = config.leader_damping_scaling; + follower_stiffness_scaling_ = config.follower_stiffness_scaling; + force_feedback_guiding_ = config.force_feedback_guiding; + force_feedback_idle_ = config.force_feedback_idle; + follower_data_.contact_force_threshold = config.follower_contact_force_threshold; + leader_data_.contact_force_threshold = config.leader_contact_force_threshold; + + dq_max_lower_[0] = config.dq_l_1; + dq_max_lower_[1] = config.dq_l_2; + dq_max_lower_[2] = config.dq_l_3; + dq_max_lower_[3] = config.dq_l_4; + dq_max_lower_[4] = config.dq_l_5; + dq_max_lower_[5] = config.dq_l_6; + dq_max_lower_[6] = config.dq_l_7; + + dq_max_upper_[0] = config.dq_u_1; + dq_max_upper_[1] = config.dq_u_2; + dq_max_upper_[2] = config.dq_u_3; + dq_max_upper_[3] = config.dq_u_4; + dq_max_upper_[4] = config.dq_u_5; + dq_max_upper_[5] = config.dq_u_6; + dq_max_upper_[6] = config.dq_u_7; + + ddq_max_lower_[0] = config.ddq_l_1; + ddq_max_lower_[1] = config.ddq_l_2; + ddq_max_lower_[2] = config.ddq_l_3; + ddq_max_lower_[3] = config.ddq_l_4; + ddq_max_lower_[4] = config.ddq_l_5; + ddq_max_lower_[5] = config.ddq_l_6; + ddq_max_lower_[6] = config.ddq_l_7; + + ddq_max_upper_[0] = config.ddq_u_1; + ddq_max_upper_[1] = config.ddq_u_2; + ddq_max_upper_[2] = config.ddq_u_3; + ddq_max_upper_[3] = config.ddq_u_4; + ddq_max_upper_[4] = config.ddq_u_5; + ddq_max_upper_[5] = config.ddq_u_6; + ddq_max_upper_[6] = config.ddq_u_7; + + ROS_INFO_NAMED(kControllerName, "Dynamic reconfigure: Controller params set."); + } + dynamic_reconfigure_mutex_.unlock(); +} + +void TeleopJointPDExampleController::getJointLimits(ros::NodeHandle& nh, + const std::vector<std::string>& joint_names, + std::array<double, 7>& upper_joint_soft_limit, + std::array<double, 7>& lower_joint_soft_limit) { + const std::string& node_namespace = nh.getNamespace(); + std::size_t found = node_namespace.find_last_of('/'); + std::string parent_namespace = node_namespace.substr(0, found); + + if (!nh.hasParam(parent_namespace + "/robot_description")) { + throw std::invalid_argument(kControllerName + ": No parameter robot_description (namespace: " + + parent_namespace + ")found to set joint limits!"); + } + + urdf::Model urdf_model; + if (!urdf_model.initParamWithNodeHandle(parent_namespace + "/robot_description", nh)) { + throw std::invalid_argument(kControllerName + + ": Could not initialize urdf model from robot_description " + "(namespace: " + + parent_namespace + ")."); + } + joint_limits_interface::SoftJointLimits soft_limits; + for (size_t i = 0; i < joint_names.size(); ++i) { + const std::string& joint_name = joint_names.at(i); + auto urdf_joint = urdf_model.getJoint(joint_name); + if (!urdf_joint) { + ROS_ERROR_STREAM_NAMED(kControllerName, + ": Could not get joint " << joint_name << " from urdf"); + } + if (!urdf_joint->safety) { + ROS_ERROR_STREAM_NAMED(kControllerName, ": Joint " << joint_name << " has no limits"); + } + if (joint_limits_interface::getSoftJointLimits(urdf_joint, soft_limits)) { + upper_joint_soft_limit[i] = soft_limits.max_position; + lower_joint_soft_limit[i] = soft_limits.min_position; + } else { + ROS_ERROR_STREAM_NAMED(kControllerName, ": Could not parse joint limit for joint " + << joint_name << " for joint limit interfaces"); + } + } +} + +void TeleopJointPDExampleController::publishLeaderTarget() { + if (leader_target_pub_.trylock()) { + for (size_t i = 0; i < 7; ++i) { + leader_target_pub_.msg_.name[i] = "panda_joint" + std::to_string(i + 1); + leader_target_pub_.msg_.position[i] = 0.0; + leader_target_pub_.msg_.velocity[i] = 0.0; + leader_target_pub_.msg_.effort[i] = leader_data_.tau_target[i]; + } + leader_target_pub_.unlockAndPublish(); + } +} + +void TeleopJointPDExampleController::publishFollowerTarget() { + if (follower_target_pub_.trylock()) { + for (size_t i = 0; i < 7; ++i) { + follower_target_pub_.msg_.name[i] = "panda_joint" + std::to_string(i + 1); + follower_target_pub_.msg_.position[i] = q_target_[i]; + follower_target_pub_.msg_.velocity[i] = dq_target_[i]; + follower_target_pub_.msg_.effort[i] = follower_data_.tau_target[i]; + } + follower_target_pub_.unlockAndPublish(); + } +} + +void TeleopJointPDExampleController::publishLeaderContact() { + if (leader_contact_pub_.trylock()) { + leader_contact_pub_.msg_.data = leader_data_.contact; + leader_contact_pub_.unlockAndPublish(); + } +} + +void TeleopJointPDExampleController::publishFollowerContact() { + if (follower_contact_pub_.trylock()) { + follower_contact_pub_.msg_.data = follower_data_.contact; + follower_contact_pub_.unlockAndPublish(); + } +} + +Vector7d TeleopJointPDExampleController::get7dParam(const std::string& param_name, + ros::NodeHandle& nh) { + auto buffer = getJointParams<double>(param_name, nh); + return Vector7d(Eigen::Map<Vector7d>(buffer.data())); +} + +Vector7d TeleopJointPDExampleController::leaderDamping(const Vector7d& dq) { + auto simple_ramp = [](const double min, const double max, const double value) -> double { + if (value >= max) { + return 1.0; + } + if (value <= min) { + return 0.0; + } + return (value - min) / (max - min); + }; + Vector7d damping; + for (size_t i = 0; i < 7; ++i) { + damping(i) = k_d_leader_lower_(i) + + simple_ramp(dq_max_leader_lower_(i), dq_max_leader_upper_(i), std::abs(dq(i))) * + (k_d_leader_upper_(i) - k_d_leader_lower_(i)); + } + return damping; +} + +void TeleopJointPDExampleController::publishMarkers() { + marker_pub_.lock(); + marker_pub_.unlockAndPublish(); +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::TeleopJointPDExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.h b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..4ddb658b2f75e44a096974f07b1945597465a851 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.h @@ -0,0 +1,222 @@ +// Copyright (c) 2020 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <franka_example_controllers/joint_wall.h> +#include <franka_example_controllers/teleop_paramConfig.h> +#include <franka_hw/franka_state_interface.h> +#include <franka_hw/trigger_rate.h> + +#include <control_msgs/GripperCommandAction.h> +#include <controller_interface/multi_interface_controller.h> +#include <dynamic_reconfigure/server.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <realtime_tools/realtime_publisher.h> +#include <ros/ros.h> +#include <sensor_msgs/JointState.h> +#include <std_msgs/Float64.h> +#include <visualization_msgs/MarkerArray.h> + +#include <Eigen/Dense> +#include <memory> +#include <mutex> +#include <vector> + +namespace franka_example_controllers { +/** + * Finite state machine that defines the states of the teleoperation phases. + * ALIGN is the initial phase, when the leader and follower align. During this phase the leader + * cannot be moved. + * TRACK is the tracking phase. + */ +enum TeleopStateMachine { + ALIGN, + TRACK, +}; + +/** + * Controller class for ros_control that allows force-feedback teleoperation of a follower arm from + * a leader arm. Smooth tracking is implemented by integrating a velocity signal, which is + * calculated by limiting and saturating the velocity of the leader arm and a drift compensation. + * The torque control of the follower arm is implemented by a simple PD-controller. + * The leader arm is slightly damped to reduce vibrations. + * Force-feedback is applied to the leader arm when the external forces on the follower arm exceed a + * configured threshold. + * While the leader arm is unguided (not in contact), the applied force-feedback will be reduced. + */ +class TeleopJointPDExampleController : public controller_interface::MultiInterfaceController< + hardware_interface::EffortJointInterface, + franka_hw::FrankaStateInterface> { + public: + /** + * Initializes the controller class to be ready to run. + * + * @param[in] robot_hw Pointer to a RobotHW class to get interfaces and resource handles. + * @param[in] node_handle Nodehandle that allows getting parameterizations from the server and + * starting publisher + */ + bool init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& node_handle) override; + + /** + * Prepares the controller for the real-time execution. This method is executed once every time + * the controller is started and runs in real-time + */ + void starting(const ros::Time& /*time*/) override; + + /** + * Computes the control-law and commands the resulting joint torques to the robots. + * + * @param[in] period The control period (here 0.001s) + */ + void update(const ros::Time& /*time*/, const ros::Duration& period) override; + + private: + using Vector6d = Eigen::Matrix<double, 6, 1>; + using Vector7d = Eigen::Matrix<double, 7, 1>; + using Matrix7d = Eigen::Matrix<double, 7, 7>; + + struct FrankaDataContainer { + std::unique_ptr<franka_hw::FrankaStateHandle> state_handle; + std::vector<hardware_interface::JointHandle> joint_handles; + + // A virtual wall to avoid joint limits. + std::unique_ptr<JointWallContainer<7>> virtual_joint_wall; + + Vector7d tau_target; // Target effort of each joint [Nm, Nm, Nm, Nm, Nm, Nm, Nm] + Vector7d tau_target_last; // Last target effort of each joint [Nm, ...] + Vector7d q; // Measured position of each joint [rad, ...] + Vector7d dq; // Measured velocity of each joint [rad/s, ...] + + double f_ext_norm; // Norm of the external (cartesian) forces vector at the EE [N] + double contact; // Contact scaling factor (values between 0 and 1) + double contact_ramp_increase{0.3}; // Parameter for contact scaling factor + double contact_force_threshold; // Parameter for contact scaling factor [N] + }; + + FrankaDataContainer leader_data_; // Container for data of the leader arm + FrankaDataContainer follower_data_; // Container for data of the follower arm + + Vector7d q_target_; // Target positions of the follower arm [rad, rad, rad, rad, rad, rad, rad] + Vector7d q_target_last_; // Last target positions of the follower arm [rad, ...] + Vector7d dq_unsaturated_; // Unsaturated target velocities of the follower arm [rad/s, ...] + Vector7d dq_target_; // Target velocities of the follower arm [rad/s, ...] + Vector7d dq_target_last_; // Last target velocities of the follower arm [rad/s, ...] + + Vector7d init_leader_q_; // Measured q of leader arm during alignment [rad] + + Vector7d dq_max_lower_; // Lower max velocities of the follower arm [rad/s, ...] + Vector7d dq_max_upper_; // Upper max velocities of the follower arm [rad/s, ...] + Vector7d ddq_max_lower_; // Lower max accelerations of the follower arm [rad/s², ...] + Vector7d ddq_max_upper_; // Upper max accelerations of the follower arm [rad/s², ...] + double velocity_ramp_shift_{0.25}; // parameter for ramping dq_max and ddq_max [rad] + double velocity_ramp_increase_{20}; // parameter for ramping dq_max and ddq_max + + // Max velocities of the follower arm during alignment [rad/s, ...] + Vector7d dq_max_align_{(Vector7d() << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1).finished()}; + // Max accelerations of the follower arm during alignment [rad/s², ...] + Vector7d ddq_max_align_{(Vector7d() << 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5).finished()}; + + Vector7d alignment_error_; // Diff between follower and leader q during alignment [rad/s, ...] + Vector7d prev_alignment_error_; // alignment_error_ in previous control loop [rad/s, ...] + + Vector7d k_p_follower_; // p-gain for follower arm + Vector7d k_d_follower_; // d-gain for follower arm + // p-gain for follower arm during alignment + Vector7d k_p_follower_align_{(Vector7d() << 45.0, 45.0, 45.0, 45.0, 18.0, 11.0, 5.0).finished()}; + // d-gain for follower arm during alignment + Vector7d k_d_follower_align_{(Vector7d() << 4.5, 4.5, 4.5, 4.5, 1.5, 1.5, 1.0).finished()}; + + Vector7d dq_max_leader_lower_; // Soft max velocities of the leader arm [rad/s, ...] + Vector7d dq_max_leader_upper_; // Hard max velocities of the leader arm [rad/s, ...] + Vector7d k_d_leader_lower_; // d-gain for leader arm when under soft-limit + Vector7d k_d_leader_upper_; // d-gain for leader arm when hard limit is reached + + Vector7d k_dq_; // gain for drift compensation in follower arm + + double force_feedback_idle_{0.5}; // Applied force-feedback, when leader arm is not guided + double force_feedback_guiding_{0.95}; // Applied force-feeback, when leader arm is guided + + double decrease_factor_{0.95}; // Param, used when (in error state) controlling torques to zero + + TeleopStateMachine current_state_{TeleopStateMachine::ALIGN}; // Current state in teleoperation + + const double kAlignmentTolerance_{1e-2}; // Tolerance to consider a joint aligned [rad] + + void initArm(hardware_interface::RobotHW* robot_hw, + ros::NodeHandle& node_handle, + FrankaDataContainer& arm_data, + const std::string& arm_id, + const std::vector<std::string>& joint_names); + + void updateArm(FrankaDataContainer& arm_data); + + Vector7d saturateAndLimit(const Vector7d& x_calc, + const Vector7d& x_last, + const Vector7d& x_max, + const Vector7d& dx_max, + double delta_t); + + double rampParameter(double x, + double neg_x_asymptote, + double pos_x_asymptote, + double shift_along_x, + double increase_factor); + + template <typename T> + std::vector<T> getJointParams(const std::string& param_name, ros::NodeHandle& nh) { + std::vector<T> vec; + if (!nh.getParam(param_name, vec) || vec.size() != 7) { + throw std::invalid_argument("TeleopJointPDExampleController: Invalid or no parameter " + + nh.getNamespace() + "/" + param_name + + " provided, aborting controller init!"); + } + return vec; + } + + Vector7d get7dParam(const std::string& param_name, ros::NodeHandle& nh); + + template <typename T> + T get1dParam(const std::string& param_name, ros::NodeHandle& nh) { + T out; + if (!nh.getParam(param_name, out)) { + throw std::invalid_argument("TeleopJointPDExampleController: Invalid or no parameter " + + nh.getNamespace() + "/" + param_name + + " provided, " + "aborting controller init!"); + } + return out; + } + + static void getJointLimits(ros::NodeHandle& nh, + const std::vector<std::string>& joint_names, + std::array<double, 7>& upper_joint_soft_limit, + std::array<double, 7>& lower_joint_soft_limit); + + Vector7d leaderDamping(const Vector7d& dq); + + // Debug tool + bool debug_{false}; + std::mutex dynamic_reconfigure_mutex_; + double leader_damping_scaling_{1.0}; + double follower_stiffness_scaling_{1.0}; + + ros::NodeHandle dynamic_reconfigure_teleop_param_node_; + std::unique_ptr<dynamic_reconfigure::Server<franka_example_controllers::teleop_paramConfig>> + dynamic_server_teleop_param_; + void teleopParamCallback(franka_example_controllers::teleop_paramConfig& config, uint32_t level); + + franka_hw::TriggerRate publish_rate_{60.0}; + realtime_tools::RealtimePublisher<sensor_msgs::JointState> leader_target_pub_; + realtime_tools::RealtimePublisher<sensor_msgs::JointState> follower_target_pub_; + realtime_tools::RealtimePublisher<std_msgs::Float64> leader_contact_pub_; + realtime_tools::RealtimePublisher<std_msgs::Float64> follower_contact_pub_; + realtime_tools::RealtimePublisher<visualization_msgs::MarkerArray> marker_pub_; + + void publishLeaderTarget(); + void publishFollowerTarget(); + void publishLeaderContact(); + void publishFollowerContact(); + void publishMarkers(); +}; +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.launch b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.launch new file mode 100644 index 0000000000000000000000000000000000000000..6406d28d1b4d29daf1ef5b1f8e2af578a519abcc --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_joint_pd_example_controller.launch @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<launch> + <arg name="leader_ip" doc="left robot from user persepective standing in front of the robots for a robot setup according to $(find franka_description)/robots/dual_panda/dual_panda_example.urdf.xacro" /> + <arg name="follower_ip" doc="right robot from user persepective standing in front of the robots for a robot setup according to $(find franka_description)/robots/dual_panda/dual_panda_example.urdf.xacro" /> + + <arg name="robot_id" default="panda_teleop" doc="name of the 2-arm robot" /> + <arg name="debug" default="false" doc="publish debug information and enable dynamic parameter tuning" /> + <arg name="rviz" default="true" doc="open rviz on launch to show the virtual robot setup" /> + <arg name="load_gripper" default="false" doc="start teleoperation for the grippers (full open/close is mirrored to follower)" /> + <arg name="gripper_homed" default="false" doc="is the gripper already homed? If not the gripper will perform an initial homing motion" /> + + <remap from="dyn_reconf_teleop_param_node" to="$(arg robot_id)/dyn_reconf_teleop_param_node" /> + <remap from="$(arg robot_id)/dyn_reconf_teleop_param_node/leader_contact_force_threshold" to="$(arg robot_id)/teleop_joint_pd_example_controller/leader/contact_force_threshold" /> + <remap from="$(arg robot_id)/dyn_reconf_teleop_param_node/follower_contact_force_threshold" to="$(arg robot_id)/teleop_joint_pd_example_controller/follower/contact_force_threshold" /> + + <include file="$(find franka_control)/launch/franka_combined_control.launch"> + <arg name="robot_id" value="$(arg robot_id)" /> + <arg name="robot_ips" value="{leader/robot_ip: $(arg leader_ip), follower/robot_ip: $(arg follower_ip)}" /> + <arg name="hw_config_file" value="$(find franka_example_controllers)/config/teleop_joint_pd_example_control_node.yaml" /> + <arg name="robot" value="$(find franka_description)/robots/dual_panda/dual_panda_example.urdf.xacro" /> + <arg name="args" value="arm_id_1:=leader arm_id_2:=follower" /> + <arg name="controllers_file" value="$(find franka_example_controllers)/config/teleop_state_controllers.yaml" /> + <arg name="controllers_to_start" value="leader_state_controller follower_state_controller" /> + <arg name="joint_states_source_list" value="[leader_state_controller/joint_states, follower_state_controller/joint_states, leader/franka_gripper/joint_states, follower/franka_gripper/joint_states]" /> + </include> + + <group ns="$(arg robot_id)"> + <include file="$(find franka_example_controllers)/launch/teleop_gripper.launch" if="$(arg load_gripper)"> + <arg name="leader_ip" value="$(arg leader_ip)" /> + <arg name="follower_ip" value="$(arg follower_ip)" /> + <arg name="leader_id" value="leader" /> + <arg name="follower_id" value="follower" /> + <arg name="gripper_homed" value="$(arg gripper_homed)" /> + </include> + + <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" /> + <rosparam param="teleop_joint_pd_example_controller/debug" subst_value="true">$(arg debug)</rosparam> + <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="teleop_joint_pd_example_controller" /> + + <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" required="false" if="$(eval arg('debug') or arg('load_gripper'))" /> + + <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/teleop_joint_pd_example.rviz" if="$(arg rviz)" /> + </group> +</launch> \ No newline at end of file diff --git a/fr3_impedance_controller_real/bak/teleop_param.cfg b/fr3_impedance_controller_real/bak/teleop_param.cfg new file mode 100755 index 0000000000000000000000000000000000000000..26166baeb929c7cdaea87fcadba2e240146436ef --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_param.cfg @@ -0,0 +1,78 @@ +#!/usr/bin/env python +PACKAGE = "franka_example_controllers" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +controller_gains = gen.add_group("Controller_Gains", type="apply") +controller_gains.add("leader_damping_scaling", double_t, 0, + "Factor to be multiplied with initial leader d_gains", + 1.0, 0.0, 8.0) +controller_gains.add( + "follower_stiffness_scaling", double_t, 0, + "Factor to be multiplied with initial p-gains of follower arm, damping will also be adapted", + 1.0, 0.1, 1.3) + +force_feedback = gen.add_group("Force_Feedback") +force_feedback.add("force_feedback_idle", double_t, 0, + "Applied feedback force when leader arm is idle", 0.5, 0.0, + 1.0) +force_feedback.add("force_feedback_guiding", double_t, 0, + "Applied feedback force when leader arm is guided", 0.98, + 0.0, 1.0) + +contact_param = gen.add_group("Cartesian_Contact") +contact_param.add( + "leader_contact_force_threshold", double_t, 0, + "Force threshold at leader endeffector to determine whether the arm is in contact.", + 4.0, 0.1, 10.0) +contact_param.add( + "follower_contact_force_threshold", double_t, 0, + "Force threshold at follower endeffector to determine whether the arm is in contact.", + 5.0, 0.1, 10.0) + +dq_max = gen.add_group("Max_Velocities") +dq_max_lower_tab = dq_max.add_group("Dq_MaxLower", type="tab") +dq_max_lower = dq_max_lower_tab.add_group("dq_max_lower", type="apply") + +dq_max_lower.add("dq_l_1", double_t, 0, "Description", 0.8, 0.1, 2.17) +dq_max_lower.add("dq_l_2", double_t, 0, "Description", 0.8, 0.1, 2.17) +dq_max_lower.add("dq_l_3", double_t, 0, "Description", 0.8, 0.1, 2.17) +dq_max_lower.add("dq_l_4", double_t, 0, "Description", 0.8, 0.1, 2.17) +dq_max_lower.add("dq_l_5", double_t, 0, "Description", 2.5, 0.1, 2.6) +dq_max_lower.add("dq_l_6", double_t, 0, "Description", 2.5, 0.1, 2.6) +dq_max_lower.add("dq_l_7", double_t, 0, "Description", 2.5, 0.1, 2.6) + +dq_max_upper_tab = dq_max.add_group("Dq_MaxUpper", type="tab") +dq_max_upper = dq_max_upper_tab.add_group("dq_max_upper", type="apply") +dq_max_upper.add("dq_u_1", double_t, 0, "Description", 2.0, 0.1, 2.17) +dq_max_upper.add("dq_u_2", double_t, 0, "Description", 2.0, 0.1, 2.17) +dq_max_upper.add("dq_u_3", double_t, 0, "Description", 2.0, 0.1, 2.17) +dq_max_upper.add("dq_u_4", double_t, 0, "Description", 2.0, 0.1, 2.17) +dq_max_upper.add("dq_u_5", double_t, 0, "Description", 2.5, 0.1, 2.6) +dq_max_upper.add("dq_u_6", double_t, 0, "Description", 2.5, 0.1, 2.6) +dq_max_upper.add("dq_u_7", double_t, 0, "Description", 2.5, 0.1, 2.6) + +ddq_max = gen.add_group("Max_Acceleration") +ddq_max_lower_tab = ddq_max.add_group("Ddq_MaxLower", type="tab") +ddq_max_lower = ddq_max_lower_tab.add_group("ddq_max_lower", type="apply") +ddq_max_lower.add("ddq_l_1", double_t, 0, "Description", 0.8, 0.1, 15.0) +ddq_max_lower.add("ddq_l_2", double_t, 0, "Description", 0.8, 0.1, 7.5) +ddq_max_lower.add("ddq_l_3", double_t, 0, "Description", 0.8, 0.1, 10.0) +ddq_max_lower.add("ddq_l_4", double_t, 0, "Description", 0.8, 0.1, 12.5) +ddq_max_lower.add("ddq_l_5", double_t, 0, "Description", 10.0, 0.1, 15.0) +ddq_max_lower.add("ddq_l_6", double_t, 0, "Description", 10.0, 0.1, 20.0) +ddq_max_lower.add("ddq_l_7", double_t, 0, "Description", 10.0, 0.1, 20.0) + +ddq_max_upper_tab = ddq_max.add_group("Ddq_MaxUpper", type="tab") +ddq_max_upper = ddq_max_upper_tab.add_group("ddq_max_upper", type="apply") +ddq_max_upper.add("ddq_u_1", double_t, 0, "Description", 6.0, 0.1, 15.0) +ddq_max_upper.add("ddq_u_2", double_t, 0, "Description", 6.0, 0.1, 7.5) +ddq_max_upper.add("ddq_u_3", double_t, 0, "Description", 6.0, 0.1, 10.0) +ddq_max_upper.add("ddq_u_4", double_t, 0, "Description", 6.0, 0.1, 12.5) +ddq_max_upper.add("ddq_u_5", double_t, 0, "Description", 15.0, 0.1, 15.0) +ddq_max_upper.add("ddq_u_6", double_t, 0, "Description", 20.0, 0.1, 20.0) +ddq_max_upper.add("ddq_u_7", double_t, 0, "Description", 20.0, 0.1, 20.0) + +exit(gen.generate(PACKAGE, "teleop_param", "teleop_param")) diff --git a/fr3_impedance_controller_real/bak/teleop_state_controllers.yaml b/fr3_impedance_controller_real/bak/teleop_state_controllers.yaml new file mode 100644 index 0000000000000000000000000000000000000000..79944ed842e5033e85e786acdd5058b38fc06f96 --- /dev/null +++ b/fr3_impedance_controller_real/bak/teleop_state_controllers.yaml @@ -0,0 +1,25 @@ +leader_state_controller: + type: franka_control/FrankaStateController + arm_id: leader + joint_names: + - leader_joint1 + - leader_joint2 + - leader_joint3 + - leader_joint4 + - leader_joint5 + - leader_joint6 + - leader_joint7 + publish_rate: 30 # [Hz] + +follower_state_controller: + type: franka_control/FrankaStateController + arm_id: follower + joint_names: + - follower_joint1 + - follower_joint2 + - follower_joint3 + - follower_joint4 + - follower_joint5 + - follower_joint6 + - follower_joint7 + publish_rate: 30 # [Hz] diff --git a/fr3_impedance_controller_real/cfg/controller_param.cfg b/fr3_impedance_controller_real/cfg/controller_param.cfg new file mode 100644 index 0000000000000000000000000000000000000000..cb9abf01e186898a869402021e8aa64a2f370e7a --- /dev/null +++ b/fr3_impedance_controller_real/cfg/controller_param.cfg @@ -0,0 +1,21 @@ +#!/usr/bin/env python +PACKAGE = "franka_example_controllers" + +from dynamic_reconfigure.parameter_generator_catkin import * + +gen = ParameterGenerator() + +gen.add("K_task_x", double_t, 0, "Cartesian translational-x stiffness", 200, 0, 400) +gen.add("K_task_y", double_t, 0, "Cartesian translational-y stiffness", 200, 0, 400) +gen.add("K_task_z", double_t, 0, "Cartesian translational-z stiffness", 200, 0, 400) +gen.add("K_task_rot", double_t, 0, "Cartesian rotational stiffness", 10, 0, 30) +gen.add("K_null", double_t, 0, "Null-space joint stiffness", 0.5, 0, 100) + +gen.add("fq", double_t, 0, "DOB cutoff frequency", 15, 0, 75) +gen.add("s1", double_t, 0, "SOSML s1 gain", 10, 0, 2000) +gen.add("s2", double_t, 0, "SOSML s2 gain", 200, 0, 2000) +gen.add("r_th", double_t, 0, "MOB residual threshold", 0, 0, 100) +gen.add("Km", double_t, 0, "MOB low-pass filter gain", 2.5, 0, 75) + +exit(gen.generate(PACKAGE, "dynamic_compliance", "controller_param")) + diff --git a/fr3_impedance_controller_real/config/franka_example_controllers.yaml b/fr3_impedance_controller_real/config/franka_example_controllers.yaml index 4cb8fa5665b64f40f8a8628dcae2b52fe9b3b169..e4127e9575ced925bd48f6b83ee4df24bfe605bf 100644 --- a/fr3_impedance_controller_real/config/franka_example_controllers.yaml +++ b/fr3_impedance_controller_real/config/franka_example_controllers.yaml @@ -1,91 +1,3 @@ -joint_velocity_example_controller: - type: franka_example_controllers/JointVelocityExampleController - arm_id: $(arg arm_id) - joint_names: - - $(arg arm_id)_joint1 - - $(arg arm_id)_joint2 - - $(arg arm_id)_joint3 - - $(arg arm_id)_joint4 - - $(arg arm_id)_joint5 - - $(arg arm_id)_joint6 - - $(arg arm_id)_joint7 - -joint_position_example_controller: - type: franka_example_controllers/JointPositionExampleController - joint_names: - - $(arg arm_id)_joint1 - - $(arg arm_id)_joint2 - - $(arg arm_id)_joint3 - - $(arg arm_id)_joint4 - - $(arg arm_id)_joint5 - - $(arg arm_id)_joint6 - - $(arg arm_id)_joint7 - -cartesian_sinpose_controller: - type: franka_example_controllers/CartesianSinPoseExampleController - arm_id: $(arg arm_id) - -cartesian_pose_example_controller: - type: franka_example_controllers/CartesianPoseExampleController - arm_id: $(arg arm_id) - -elbow_example_controller: - type: franka_example_controllers/ElbowExampleController - arm_id: $(arg arm_id) - -cartesian_velocity_example_controller: - type: franka_example_controllers/CartesianVelocityExampleController - arm_id: $(arg arm_id) - -model_example_controller: - type: franka_example_controllers/ModelExampleController - arm_id: $(arg arm_id) - -force_example_controller: - type: franka_example_controllers/ForceExampleController - arm_id: $(arg arm_id) - joint_names: - - $(arg arm_id)_joint1 - - $(arg arm_id)_joint2 - - $(arg arm_id)_joint3 - - $(arg arm_id)_joint4 - - $(arg arm_id)_joint5 - - $(arg arm_id)_joint6 - - $(arg arm_id)_joint7 - -joint_impedance_example_controller: - type: franka_example_controllers/JointImpedanceExampleController - arm_id: $(arg arm_id) - joint_names: - - $(arg arm_id)_joint1 - - $(arg arm_id)_joint2 - - $(arg arm_id)_joint3 - - $(arg arm_id)_joint4 - - $(arg arm_id)_joint5 - - $(arg arm_id)_joint6 - - $(arg arm_id)_joint7 - k_gains: - - 600.0 - - 600.0 - - 600.0 - - 600.0 - - 250.0 - - 150.0 - - 50.0 - d_gains: - - 50.0 - - 50.0 - - 50.0 - - 20.0 - - 20.0 - - 20.0 - - 10.0 - radius: 0.1 - acceleration_time: 2.0 - vel_max: 0.15 - publish_rate: 10.0 - coriolis_factor: 1.0 - cartesian_impedance_example_controller: type: franka_example_controllers/CartesianImpedanceExampleController arm_id: $(arg arm_id) @@ -98,82 +10,170 @@ cartesian_impedance_example_controller: - $(arg arm_id)_joint6 - $(arg arm_id)_joint7 -dual_arm_cartesian_impedance_example_controller: - type: franka_example_controllers/DualArmCartesianImpedanceExampleController - right: - arm_id: panda_1 - joint_names: - - panda_1_joint1 - - panda_1_joint2 - - panda_1_joint3 - - panda_1_joint4 - - panda_1_joint5 - - panda_1_joint6 - - panda_1_joint7 - left: - arm_id: panda_2 - joint_names: - - panda_2_joint1 - - panda_2_joint2 - - panda_2_joint3 - - panda_2_joint4 - - panda_2_joint5 - - panda_2_joint6 - - panda_2_joint7 - -teleop_joint_pd_example_controller: - type: franka_example_controllers/TeleopJointPDExampleController - leader: - arm_id: leader - joint_names: - - leader_joint1 - - leader_joint2 - - leader_joint3 - - leader_joint4 - - leader_joint5 - - leader_joint6 - - leader_joint7 - # WARNING: Varying the following parameters may result in instability! - d_gains_lower: [1.0, 1.0, 1.0, 1.0, 0.33, 0.33, 0.17] - d_gains_upper: [35.0, 35.0, 35.0, 35.0, 10.0, 10.0, 8.0] - dq_max_lower: [1.3, 1.3, 1.3, 1.3, 1.4, 1.4, 1.4] # [rad/s] - dq_max_upper: [1.9, 1.9, 1.9, 1.9, 2.2, 2.2, 2.2] # [rad/s] - contact_force_threshold: 4.0 # [N] - - follower: - arm_id: follower - joint_names: - - follower_joint1 - - follower_joint2 - - follower_joint3 - - follower_joint4 - - follower_joint5 - - follower_joint6 - - follower_joint7 - # WARNING: Varying the following parameters may result in instability! - p_gains: [900.0, 900.0, 900.0, 900.0, 375.0, 225.0, 100.0] - d_gains: [45.0, 45.0, 45.0, 45.0, 15.0, 15.0, 10.0] - drift_comp_gains: [4.3, 4.3, 4.3, 4.3, 4.3, 4.3, 4.3] - dq_max_lower: [0.8, 0.8, 0.8, 0.8, 2.5, 2.5, 2.5] # [rad/s] - dq_max_upper: [2.0, 2.0, 2.0, 2.0, 2.5, 2.5, 2.5] # [rad/s] - ddq_max_lower: [0.8, 0.8, 0.8, 0.8, 10.0, 10.0, 10.0] # [rad/s^2] - ddq_max_upper: [6.0, 6.0, 6.0, 6.0, 15.0, 20.0, 20.0] # [rad/s^2] - contact_force_threshold: 5.0 # [N] - -spacenav_teleop_twist_controller: - type: franka_example_controllers/SpacenavTeleopTwistController - arm_id: $(arg arm_id) - linear_gain: $(arg linear_gain) - angular_gain: $(arg angular_gain) - -cartesian_pose_controller: - type: franka_example_controllers/CartesianPoseController - arm_id: $(arg arm_id) - -cartesian_traj_controller: - type: franka_example_controllers/CartesianTrajController - arm_id: $(arg arm_id) - -cartesian_traj_twist_correct_controller: - type: franka_example_controllers/CartesianTrajTwistCorrectController - arm_id: $(arg arm_id) +# joint_velocity_example_controller: +# type: franka_example_controllers/JointVelocityExampleController +# arm_id: $(arg arm_id) +# joint_names: +# - $(arg arm_id)_joint1 +# - $(arg arm_id)_joint2 +# - $(arg arm_id)_joint3 +# - $(arg arm_id)_joint4 +# - $(arg arm_id)_joint5 +# - $(arg arm_id)_joint6 +# - $(arg arm_id)_joint7 + +# joint_position_example_controller: +# type: franka_example_controllers/JointPositionExampleController +# joint_names: +# - $(arg arm_id)_joint1 +# - $(arg arm_id)_joint2 +# - $(arg arm_id)_joint3 +# - $(arg arm_id)_joint4 +# - $(arg arm_id)_joint5 +# - $(arg arm_id)_joint6 +# - $(arg arm_id)_joint7 + +# cartesian_sinpose_controller: +# type: franka_example_controllers/CartesianSinPoseExampleController +# arm_id: $(arg arm_id) + +# cartesian_pose_example_controller: +# type: franka_example_controllers/CartesianPoseExampleController +# arm_id: $(arg arm_id) + +# elbow_example_controller: +# type: franka_example_controllers/ElbowExampleController +# arm_id: $(arg arm_id) + +# cartesian_velocity_example_controller: +# type: franka_example_controllers/CartesianVelocityExampleController +# arm_id: $(arg arm_id) + +# model_example_controller: +# type: franka_example_controllers/ModelExampleController +# arm_id: $(arg arm_id) + +# force_example_controller: +# type: franka_example_controllers/ForceExampleController +# arm_id: $(arg arm_id) +# joint_names: +# - $(arg arm_id)_joint1 +# - $(arg arm_id)_joint2 +# - $(arg arm_id)_joint3 +# - $(arg arm_id)_joint4 +# - $(arg arm_id)_joint5 +# - $(arg arm_id)_joint6 +# - $(arg arm_id)_joint7 + +# joint_impedance_example_controller: +# type: franka_example_controllers/JointImpedanceExampleController +# arm_id: $(arg arm_id) +# joint_names: +# - $(arg arm_id)_joint1 +# - $(arg arm_id)_joint2 +# - $(arg arm_id)_joint3 +# - $(arg arm_id)_joint4 +# - $(arg arm_id)_joint5 +# - $(arg arm_id)_joint6 +# - $(arg arm_id)_joint7 +# k_gains: +# - 600.0 +# - 600.0 +# - 600.0 +# - 600.0 +# - 250.0 +# - 150.0 +# - 50.0 +# d_gains: +# - 50.0 +# - 50.0 +# - 50.0 +# - 20.0 +# - 20.0 +# - 20.0 +# - 10.0 +# radius: 0.1 +# acceleration_time: 2.0 +# vel_max: 0.15 +# publish_rate: 10.0 +# coriolis_factor: 1.0 + +# dual_arm_cartesian_impedance_example_controller: +# type: franka_example_controllers/DualArmCartesianImpedanceExampleController +# right: +# arm_id: panda_1 +# joint_names: +# - panda_1_joint1 +# - panda_1_joint2 +# - panda_1_joint3 +# - panda_1_joint4 +# - panda_1_joint5 +# - panda_1_joint6 +# - panda_1_joint7 +# left: +# arm_id: panda_2 +# joint_names: +# - panda_2_joint1 +# - panda_2_joint2 +# - panda_2_joint3 +# - panda_2_joint4 +# - panda_2_joint5 +# - panda_2_joint6 +# - panda_2_joint7 + +# teleop_joint_pd_example_controller: +# type: franka_example_controllers/TeleopJointPDExampleController +# leader: +# arm_id: leader +# joint_names: +# - leader_joint1 +# - leader_joint2 +# - leader_joint3 +# - leader_joint4 +# - leader_joint5 +# - leader_joint6 +# - leader_joint7 +# # WARNING: Varying the following parameters may result in instability! +# d_gains_lower: [1.0, 1.0, 1.0, 1.0, 0.33, 0.33, 0.17] +# d_gains_upper: [35.0, 35.0, 35.0, 35.0, 10.0, 10.0, 8.0] +# dq_max_lower: [1.3, 1.3, 1.3, 1.3, 1.4, 1.4, 1.4] # [rad/s] +# dq_max_upper: [1.9, 1.9, 1.9, 1.9, 2.2, 2.2, 2.2] # [rad/s] +# contact_force_threshold: 4.0 # [N] + +# follower: +# arm_id: follower +# joint_names: +# - follower_joint1 +# - follower_joint2 +# - follower_joint3 +# - follower_joint4 +# - follower_joint5 +# - follower_joint6 +# - follower_joint7 +# # WARNING: Varying the following parameters may result in instability! +# p_gains: [900.0, 900.0, 900.0, 900.0, 375.0, 225.0, 100.0] +# d_gains: [45.0, 45.0, 45.0, 45.0, 15.0, 15.0, 10.0] +# drift_comp_gains: [4.3, 4.3, 4.3, 4.3, 4.3, 4.3, 4.3] +# dq_max_lower: [0.8, 0.8, 0.8, 0.8, 2.5, 2.5, 2.5] # [rad/s] +# dq_max_upper: [2.0, 2.0, 2.0, 2.0, 2.5, 2.5, 2.5] # [rad/s] +# ddq_max_lower: [0.8, 0.8, 0.8, 0.8, 10.0, 10.0, 10.0] # [rad/s^2] +# ddq_max_upper: [6.0, 6.0, 6.0, 6.0, 15.0, 20.0, 20.0] # [rad/s^2] +# contact_force_threshold: 5.0 # [N] + +# spacenav_teleop_twist_controller: +# type: franka_example_controllers/SpacenavTeleopTwistController +# arm_id: $(arg arm_id) +# linear_gain: $(arg linear_gain) +# angular_gain: $(arg angular_gain) + +# cartesian_pose_controller: +# type: franka_example_controllers/CartesianPoseController +# arm_id: $(arg arm_id) + +# cartesian_traj_controller: +# type: franka_example_controllers/CartesianTrajController +# arm_id: $(arg arm_id) + +# cartesian_traj_twist_correct_controller: +# type: franka_example_controllers/CartesianTrajTwistCorrectController + # arm_id: $(arg arm_id) diff --git a/fr3_impedance_controller_real/default.nix b/fr3_impedance_controller_real/default.nix index 8c7ab949d7951526a050262d6bb70bba529b0e1d..4d5adaa20529f95f86d6718a1563432b6f46be5a 100644 --- a/fr3_impedance_controller_real/default.nix +++ b/fr3_impedance_controller_real/default.nix @@ -12,21 +12,25 @@ , franka-description , franka-gripper , franka-hw -, franka-example-controllers , libfranka , hardware-interface , joint-limits-interface , message-generation , message-runtime , geometry-msgs +, tf2-geometry-msgs , visualization-msgs , roscpp , rospy , tf , tf-conversions , urdf +, spacenav-node +, rqt-reconfigure +#, rviz , common # shared library from the project +, fr3-custom-msgs }: buildRosPackage { @@ -46,7 +50,6 @@ buildRosPackage { franka-gripper franka-hw libfranka - franka-example-controllers geometry-msgs hardware-interface joint-limits-interface @@ -57,14 +60,18 @@ buildRosPackage { roscpp rospy tf tf-conversions + tf2-geometry-msgs urdf visualization-msgs + spacenav-node + rqt-reconfigure + #rviz common + fr3-custom-msgs ]; nativeBuildInputs = [ catkin ]; - meta = { description = "Impedance controller to run on the Franka Emika FR3"; }; diff --git a/fr3_impedance_controller_real/fr3_impedance_controller_real_plugin.xml b/fr3_impedance_controller_real/fr3_impedance_controller_real_plugin.xml deleted file mode 100644 index 1bec1f5d6871804f5fca75b9f2cf7b1d414278dd..0000000000000000000000000000000000000000 --- a/fr3_impedance_controller_real/fr3_impedance_controller_real_plugin.xml +++ /dev/null @@ -1,84 +0,0 @@ -<library path="lib/libfranka_example_controllers"> - <class name="franka_example_controllers/JointVelocityExampleController" type="franka_example_controllers::JointVelocityExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on joint velocities to demonstrate correct usage - </description> - </class> - <class name="franka_example_controllers/JointPositionExampleController" type="franka_example_controllers::JointPositionExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on joint positions to demonstrate correct usage - </description> - </class> - <class name="franka_example_controllers/CartesianPoseExampleController" type="franka_example_controllers::CartesianPoseExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on cartesian poses to demonstrate correct usage - </description> - </class> - <!-- ADD here --> - <class name="franka_example_controllers/CartesianSinPoseExampleController" type="franka_example_controllers::CartesianSinPoseExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on cartesian poses to demonstrate correct usage - </description> - </class> - <!-- --> - <class name="franka_example_controllers/CartesianVelocityExampleController" type="franka_example_controllers::CartesianVelocityExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on cartesian velocities to demonstrate correct usage - </description> - </class> - <class name="franka_example_controllers/ElbowExampleController" type="franka_example_controllers::ElbowExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that executes a short motion based on cartesian poses and elbow to demonstrate correct usage - </description> - </class> - <class name="franka_example_controllers/ModelExampleController" type="franka_example_controllers::ModelExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that evaluates and prints the dynamic model of Franka - </description> - </class> - <class name="franka_example_controllers/JointImpedanceExampleController" type="franka_example_controllers::JointImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that tracks a cartesian path with a joint impedance controller that compensates coriolis torques. The torque commands are compared to measured torques in Console outputs. - </description> - </class> - <class name="franka_example_controllers/CartesianImpedanceExampleController" type="franka_example_controllers::CartesianImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that renders a spring damper system in cartesian space. Compliance parameters and the equilibrium pose can be modified online with dynamic reconfigure and an interactive marker respectively. - </description> - </class> - <class name="franka_example_controllers/ForceExampleController" type="franka_example_controllers::ForceExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A PI controller that applies a force corresponding to a user-provided desired mass in the z axis. The desired mass value can be modified online with dynamic reconfigure. - </description> - </class> - <class name="franka_example_controllers/DualArmCartesianImpedanceExampleController" type="franka_example_controllers::DualArmCartesianImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A controller that renders Cartesian impedance based tracking of separate target poses for 2 panda arms. - </description> - </class> - <class name="franka_example_controllers/TeleopJointPDExampleController" type="franka_example_controllers::TeleopJointPDExampleController" base_class_type="controller_interface::ControllerBase"> - <description> - A PD controller that tracks position and velocity of the leader arm and applies it to the follower arm. It also applies force-feedback to the leader arm. - </description> - </class> - <class name="franka_example_controllers/SpacenavTeleopTwistController" type="franka_example_controllers::SpacenavTeleopTwistController" base_class_type="controller_interface::ControllerBase"> - <description> - A Controller that takes Twist Input from the 6DoF spacenav mouse and sends these to the robot. - </description> - </class> - <class name="franka_example_controllers/CartesianPoseController" type="franka_example_controllers::CartesianPoseController" base_class_type="controller_interface::ControllerBase"> - <description> - A Controller that takes single cartesian pose (currently only position, no orientation). - </description> - </class> - <class name="franka_example_controllers/CartesianTrajController" type="franka_example_controllers::CartesianTrajController" base_class_type="controller_interface::ControllerBase"> - <description> - A Controller that takes PoseArray (pos traj). - </description> - </class> - <class name="franka_example_controllers/CartesianTrajTwistCorrectController" type="franka_example_controllers::CartesianTrajTwistCorrectController" base_class_type="controller_interface::ControllerBase"> - <description> - A Controller that takes PoseArray (pos traj) and can correct the unsmoothness of the traj with the spacenav twist commands. - </description> - </class> -</library> diff --git a/fr3_impedance_controller_real/franka_example_controllers_plugin.xml b/fr3_impedance_controller_real/franka_example_controllers_plugin.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba2baaedf3be020c491682815892aded108636ff --- /dev/null +++ b/fr3_impedance_controller_real/franka_example_controllers_plugin.xml @@ -0,0 +1,83 @@ +<library path="lib/libfranka_example_controllers"> + <class name="franka_example_controllers/CartesianImpedanceExampleController" type="franka_example_controllers::CartesianImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that renders a spring damper system in cartesian space. Compliance parameters and the equilibrium pose can be modified online with dynamic reconfigure and an interactive marker respectively. + </description> + </class> + <!-- <class name="franka_example_controllers/JointVelocityExampleController" type="franka_example_controllers::JointVelocityExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on joint velocities to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/JointPositionExampleController" type="franka_example_controllers::JointPositionExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on joint positions to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianPoseExampleController" type="franka_example_controllers::CartesianPoseExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on cartesian poses to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianSinPoseExampleController" type="franka_example_controllers::CartesianSinPoseExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on cartesian poses to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianVelocityExampleController" type="franka_example_controllers::CartesianVelocityExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on cartesian velocities to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/ElbowExampleController" type="franka_example_controllers::ElbowExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that executes a short motion based on cartesian poses and elbow to demonstrate correct usage + </description> + </class> --> + <!-- <class name="franka_example_controllers/ModelExampleController" type="franka_example_controllers::ModelExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that evaluates and prints the dynamic model of Franka + </description> + </class> --> + <!-- <class name="franka_example_controllers/JointImpedanceExampleController" type="franka_example_controllers::JointImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that tracks a cartesian path with a joint impedance controller that compensates coriolis torques. The torque commands are compared to measured torques in Console outputs. + </description> + </class> --> + + <!-- <class name="franka_example_controllers/ForceExampleController" type="franka_example_controllers::ForceExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A PI controller that applies a force corresponding to a user-provided desired mass in the z axis. The desired mass value can be modified online with dynamic reconfigure. + </description> + </class> --> + <!-- <class name="franka_example_controllers/DualArmCartesianImpedanceExampleController" type="franka_example_controllers::DualArmCartesianImpedanceExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A controller that renders Cartesian impedance based tracking of separate target poses for 2 panda arms. + </description> + </class> --> + <!-- <class name="franka_example_controllers/TeleopJointPDExampleController" type="franka_example_controllers::TeleopJointPDExampleController" base_class_type="controller_interface::ControllerBase"> + <description> + A PD controller that tracks position and velocity of the leader arm and applies it to the follower arm. It also applies force-feedback to the leader arm. + </description> + </class> --> + <!-- <class name="franka_example_controllers/SpacenavTeleopTwistController" type="franka_example_controllers::SpacenavTeleopTwistController" base_class_type="controller_interface::ControllerBase"> + <description> + A Controller that takes Twist Input from the 6DoF spacenav mouse and sends these to the robot. + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianPoseController" type="franka_example_controllers::CartesianPoseController" base_class_type="controller_interface::ControllerBase"> + <description> + A Controller that takes single cartesian pose (currently only position, no orientation). + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianTrajController" type="franka_example_controllers::CartesianTrajController" base_class_type="controller_interface::ControllerBase"> + <description> + A Controller that takes PoseArray (pos traj). + </description> + </class> --> + <!-- <class name="franka_example_controllers/CartesianTrajTwistCorrectController" type="franka_example_controllers::CartesianTrajTwistCorrectController" base_class_type="controller_interface::ControllerBase"> + <description> + A Controller that takes PoseArray (pos traj) and can correct the unsmoothness of the traj with the spacenav twist commands. + </description> + </class> --> +</library> diff --git a/fr3_impedance_controller_real/include/fr3_impedance_controller_real/fr3_impedance_controller_real.hpp b/fr3_impedance_controller_real/include/fr3_impedance_controller_real/fr3_impedance_controller_real.hpp deleted file mode 100644 index bfe738d9b80449658c32b9823d5dfe913f019099..0000000000000000000000000000000000000000 --- a/fr3_impedance_controller_real/include/fr3_impedance_controller_real/fr3_impedance_controller_real.hpp +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2017 Franka Emika GmbH -// Use of this source code is governed by the Apache-2.0 license, see LICENSE -#pragma once - -#include <memory> -#include <mutex> -#include <string> -#include <vector> - -#include <controller_interface/multi_interface_controller.h> -#include <dynamic_reconfigure/server.h> -#include <geometry_msgs/PoseStamped.h> -#include <hardware_interface/joint_command_interface.h> -#include <hardware_interface/robot_hw.h> -#include <ros/node_handle.h> -#include <ros/time.h> -#include <Eigen/Dense> - -#include <geometry_msgs/Twist.h> // for spacenave teleop -#include <sensor_msgs/Joy.h> // for joystick command -#include "eigen_types.hpp" // for custom Eigen types -#include "orientation_utilities.hpp" // for orientation computation - -#include <franka_example_controllers/compliance_paramConfig.h> -#include <franka_hw/franka_model_interface.h> -#include <franka_hw/franka_state_interface.h> - -namespace franka_example_controllers -{ -class CartesianImpedanceExampleController : - public controller_interface::MultiInterfaceController<franka_hw::FrankaModelInterface, - hardware_interface::EffortJointInterface, - franka_hw::FrankaStateInterface> -{ -public: - bool init(hardware_interface::RobotHW * robot_hw, ros::NodeHandle & node_handle) override; - void starting(const ros::Time &) override; - // void stopping(const ros::Time&) override; - void update(const ros::Time &, const ros::Duration & period) override; - -private: - // Saturation - Eigen::Matrix<double, 7, 1> saturateTorqueRate( - const Eigen::Matrix<double, 7, 1> & tau_d_calculated, - const Eigen::Matrix<double, 7, 1> & tau_J_d); // NOLINT (readability-identifier-naming) - - std::unique_ptr<franka_hw::FrankaStateHandle> state_handle_; - std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; - std::vector<hardware_interface::JointHandle> joint_handles_; - - double filter_params_{ 0.005 }; - double nullspace_stiffness_{ 20.0 }; - double nullspace_stiffness_target_{ 20.0 }; - const double delta_tau_max_{ 1.0 }; - - const std::vector<double> fric_phi1{ - 0.54615, 0.87224, 0.64068, 1.2794, 0.83904, 0.30301, 0.56489 - }; - const std::vector<double> fric_phi2{ 5.1181, 9.0657, 10.136, 5.590, 8.3469, 17.133, 10.336 }; - // const std::vector<double> fric_phi3{0.039533, 0.025882, -0.04607, 0.036194, 0.026226, - // -0.021047, 0.0035526}; - const std::vector<double> fric_phi3{ - 0., 0., 0., 0., 0., 0., 0., - }; - - Eigen::Matrix<double, 6, 6> cartesian_stiffness_; - Eigen::Matrix<double, 6, 6> cartesian_stiffness_target_; - Eigen::Matrix<double, 6, 6> cartesian_damping_; - Eigen::Matrix<double, 6, 6> cartesian_damping_target_; - Eigen::Matrix<double, 7, 1> q_d_nullspace_; - Eigen::Vector3d position_d_; - Eigen::Quaterniond orientation_d_; - std::mutex position_and_orientation_d_target_mutex_; - Eigen::Vector3d position_d_target_; - Eigen::Quaterniond orientation_d_target_; - - // Dynamic reconfigure - std::unique_ptr<dynamic_reconfigure::Server<franka_example_controllers::compliance_paramConfig>> - dynamic_server_compliance_param_; - ros::NodeHandle dynamic_reconfigure_compliance_param_node_; - void complianceParamCallback(franka_example_controllers::compliance_paramConfig & config, - uint32_t level); - - // Equilibrium pose subscriber - ros::Subscriber sub_equilibrium_pose_; - void equilibriumPoseCallback(const geometry_msgs::PoseStampedConstPtr & msg); - - /* Target EE Pose command */ - // bool b_is_marker_mode_ = false; - // ros::Subscriber sub_interactive_marker_; - // std::mutex target_ee_pose_mutex_; - // Vec3<double> ee_pos_world_des_target_; - // Quat<double> ee_quat_world_des_target_; - - /* spacenav target twist subscriber */ - ros::Subscriber sub_target_twist_; - void subscribe_target_twist(const geometry_msgs::TwistConstPtr & msg); - // Vec6<double> ee_vel_world_target_; - Vec6<double> ee_vel_scale_; - Vec6<double> ee_vel_world_des_, ee_vel_world_des_prev_; - Vec6<double> ee_acc_world_des_, ee_acc_world_des_prev_; - Vec3<double> ee_pos_world_des_; - Quat<double> ee_quat_world_des_; - Vec3<double> ee_rpy_world_des_, ee_rpy_world_des_prev_; - Vec3<double> ee_rpy_world_mes_, ee_rpy_world_mes_prev_; - - Vec6<double> fr3_vel_limit_; - Vec6<double> fr3_acc_limit_; - Vec6<double> fr3_jrk_limit_; - - ros::Subscriber sub_joy_; - void subscribe_joy_command(const sensor_msgs::JoyConstPtr & msg); - std::array<int, 2> btn_cmd_; -}; - -} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/include/franka_example_controllers/cartesian_impedance_example_controller.h b/fr3_impedance_controller_real/include/franka_example_controllers/cartesian_impedance_example_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..024d62d53695b06276835ebbf935fde6b3485fc1 --- /dev/null +++ b/fr3_impedance_controller_real/include/franka_example_controllers/cartesian_impedance_example_controller.h @@ -0,0 +1,202 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#pragma once + +#include <memory> +#include <mutex> +#include <string> +#include <vector> + +/* ROS packages */ +#include <controller_interface/multi_interface_controller.h> +#include <dynamic_reconfigure/server.h> +#include <hardware_interface/joint_command_interface.h> +#include <hardware_interface/robot_hw.h> +#include <ros/node_handle.h> +#include <ros/time.h> + +#include <geometry_msgs/PoseStamped.h> // interactive marker +#include <geometry_msgs/Twist.h> // spacenave teleop +#include <sensor_msgs/Joy.h> // joystick +#include "fr3_custom_msgs/ControllerState.h" // custom message + +#include <franka_hw/franka_model_interface.h> +#include <franka_hw/franka_state_interface.h> + +// #include <franka_example_controllers/compliance_paramConfig.h> +#include "franka_example_controllers/controller_paramConfig.h" + +/* Dependencies */ +#include "pinocchio/algorithm/crba.hpp" // joint-space inertia (upper-triangle) +#include "pinocchio/algorithm/frames.hpp" // +#include "pinocchio/algorithm/jacobian.hpp" // +#include "pinocchio/algorithm/kinematics.hpp" // +#include "pinocchio/algorithm/rnea.hpp" // Coriolis, gravity, joint torque +#include "pinocchio/autodiff/casadi.hpp" // +#include "pinocchio/multibody/data.hpp" +#include "pinocchio/multibody/model.hpp" +#include "pinocchio/parsers/urdf.hpp" + +/* Custom libraries */ +#include "DisturbanceObserver.hpp" +#include "ImpedanceController.hpp" +#include "MomentumObserver.hpp" +#include "SlidingModeObserver.hpp" + +#include "eigen_types.hpp" +#include "Timer.hpp" + +namespace franka_example_controllers +{ +class CartesianImpedanceExampleController : + public controller_interface::MultiInterfaceController<franka_hw::FrankaModelInterface, + hardware_interface::EffortJointInterface, + franka_hw::FrankaStateInterface> +{ +public: + bool init(hardware_interface::RobotHW * robot_hw, ros::NodeHandle & node_handle) override; + void starting(const ros::Time &) override; + void update(const ros::Time &, const ros::Duration & period) override; + // void stopping(const ros::Time &) override; + +private: + std::unique_ptr<franka_hw::FrankaStateHandle> state_handle_; + std::unique_ptr<franka_hw::FrankaModelHandle> model_handle_; + std::vector<hardware_interface::JointHandle> joint_handles_; + + Timer loop_timer_; + double max_exec_time_ = 0.0; + // int tick_ = 0; // loop iteration + double loop_time_ = 0.0; // loop elapsed time + + /* Robot Model */ + // NOTE: you need to specify absolute path (not relative) for URDF file. + std::string repo_path_ = "/home/ipk410/nix-project/impedance_controller"; + std::string urdf_filename_ = std::string(repo_path_ + "/assets/model/fr3_franka_hand.urdf"); + pinocchio::Model model_; + pinocchio::Data data_; + int ee_id_; + + //* ----- Constants ------------------------------------------------------------------------------ + const double delta_tau_max_{ 1.0 }; + const double twist_scale_[6] = { 0.15, 0.15, 0.15, 0.8, 0.8, 0.8 }; + const double alpha_ = 0.005; // targeting filter coefficient + // const double spacenav_cmd_max_{ 0.6834 }; + + // TODO: make it as rosparam (optional) + const Vec6<double> fr3_vel_limit_ = // [m(rad)/s] + (Vec6<double>() << 3.0, 3.0, 3.0, 2.5, 2.5, 2.5).finished(); + const Vec6<double> fr3_acc_limit_ = // [m(rad)/s^2] + (Vec6<double>() << 9.0, 9.0, 9.0, 17.0, 17.0, 17.0).finished(); + const Vec6<double> fr3_jrk_limit_ = // [m(rad)/s^3] + (Vec6<double>() << 4500.0, 4500.0, 4500.0, 8500.0, 8500.0, 8500.0).finished(); + + //* ----- Booleans to control -------------------------------------------------------------------- + bool b_count_loop_time_ = false; + + bool b_dob_applied_ = false; + bool b_sosml_applied_ = false; + bool b_mob_applied_ = false; + + //* ----- Publisher & Subscriber ----------------------------------------------------------------- + /* Controller state publisher */ + ros::Publisher pub_ctrl_state_; + fr3_custom_msgs::ControllerState msg_ctrl_state_; + + /* Target EE Twist & Gripper command from Spacenav (or PS3) Joystick */ + ros::Subscriber sub_target_twist_; + ros::Subscriber sub_joy_; + // std::array<int, 2> btn_cmd_; + Vec6<double> ee_vel_world_target_; + + /* Target EE Pose command from Interactive Marker */ + // ros::Subscriber sub_ee_pose_; + // std::mutex target_ee_pose_mutex_; + // Vec3<double> ee_pos_world_target_; + // Quat<double> ee_quat_world_target_; + // bool b_is_marker_mode_ = false; + + //* ----- Control Parameters --------------------------------------------------------------------- + /* Dynamic Reconfigure Server */ + std::unique_ptr<dynamic_reconfigure::Server<franka_example_controllers::controller_paramConfig>> + ctrl_param_server_; + ros::NodeHandle ctrl_param_node_; + + Mat6<double> K_task_, K_task_target_; // cartesian stiffness [N/m, Nm/rad] + Mat6<double> D_task_, D_task_target_; // cartesian damping [Ns/m, Nms/rad] + Mat7<double> K_null_, K_null_target_; // null-sapce stiffness [Nm/rad] + Mat7<double> D_null_, D_null_target_; // null-space damping [Nms/rad] + + Vec6<double> fq_, fq_target_; // DOB low-pass filter cutoff-frequency [Hz] + Vec7<double> s1_, s1_target_, s2_, s2_target_; // SOSML tuning parameters [Hz^2] + Vec7<double> t1_, t1_target_, t2_, t2_target_; // SOSML tuning parameters [Hz] + Vec7<double> r_th_, r_th_target_; // MOB residual threshold [Nm] + Vec7<double> km_, km_target_; // MOB low-pass filter gain [rad/s] + + //* ----- Control States ------------------------------------------------------------------------- + /* Joint states */ + Vec7<double> q_mes_; + Vec7<double> q_null_des_; + Vec7<double> dq_mes_, dq_mes_prev_; + Vec7<double> ddq_eul_, ddq_eul_prev_; // joint accel using backward Euler method + + /* Desired EE states */ + Vec3<double> ee_pos_world_des_; + Quat<double> ee_quat_world_des_; + Vec3<double> ee_rpy_world_des_, ee_rpy_world_des_prev_; + Vec6<double> ee_vel_world_des_, ee_vel_world_des_prev_; + Vec6<double> ee_acc_world_des_, ee_acc_world_des_prev_; + + /* Measured EE states */ + Vec3<double> ee_pos_world_mes_; + Quat<double> ee_quat_world_mes_; + Vec3<double> ee_rpy_world_mes_, ee_rpy_world_mes_prev_; + Vec6<double> ee_vel_world_mes_, ee_vel_world_mes_prev_; // v = J * dq + Vec6<double> ee_acc_world_eul_, ee_acc_world_eul_prev_; // task accel by backward Euler method + + /* Controllers */ + std::unique_ptr<ImpedanceController<double>> imp_; + std::unique_ptr<DisturbanceObserver<double>> dob_; + Vec7<double> tau_d_hat_dob_; + Vec6<double> Fd_hat_dob_; + + std::unique_ptr<SlidingModeObserver<double>> sosml_; + Vec7<double> ddq_hat_sosml_; + Vec7<double> tau_d_hat_sosml_; + Vec6<double> ee_acc_world_hat_sosml_; + Vec6<double> Fd_hat_sosml_; + + std::unique_ptr<MomentumObserver<double>> mob_; + Vec7<double> h_mes_, h_mes_prev_; // General Momentum + Vec7<double> ddq_hat_mob_; + Vec6<double> ee_acc_world_hat_mob_; + Vec7<double> tau_d_hat_mob_; + Vec6<double> Fd_hat_mob_; + + Vec6<double> Fd_hat_fr_; // franka's external force estimation + +public: + //* ----- SUBSCRIBE CALLBACK --------------------------------------------------------------------- + void subscribe_target_twist(const geometry_msgs::TwistConstPtr & msg); + void subscribe_joy_command(const sensor_msgs::JoyConstPtr & msg); + + //* ----- PARAMETER SERVER CALLBACK -------------------------------------------------------------- + void request_controller_parameters(franka_example_controllers::controller_paramConfig & config, + uint32_t level); + + //* ----- METHODS -------------------------------------------------------------------------------- + void init_states(); + void update_previous_states(); + void publish_controller_state(); + + /* joint torque saturation */ + Eigen::Matrix<double, 7, 1> saturateTorqueRate( + const Eigen::Matrix<double, 7, 1> & tau_d_calculated, + const Eigen::Matrix<double, 7, 1> & tau_J_d); // NOLINT (readability-identifier-naming) + + //* ----- PRINTER -------------------------------------------------------------------------------- + void print_end_effector_states(); + void print_dynamics(); +}; + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/include/franka_example_controllers/pseudo_inversion.h b/fr3_impedance_controller_real/include/franka_example_controllers/pseudo_inversion.h new file mode 100644 index 0000000000000000000000000000000000000000..c820927483012b31290f30226806b70a3c917937 --- /dev/null +++ b/fr3_impedance_controller_real/include/franka_example_controllers/pseudo_inversion.h @@ -0,0 +1,30 @@ +// Author: Enrico Corvaglia +// https://github.com/CentroEPiaggio/kuka-lwr/blob/master/lwr_controllers/include/utils/pseudo_inversion.h +// File provided under public domain +// pseudo_inverse() computes the pseudo inverse of matrix M_ using SVD decomposition (can choose +// between damped and not) +// returns the pseudo inverted matrix M_pinv_ + +#pragma once + +#include <Eigen/Core> +#include <Eigen/LU> +#include <Eigen/SVD> + +namespace franka_example_controllers { + +inline void pseudoInverse(const Eigen::MatrixXd& M_, Eigen::MatrixXd& M_pinv_, bool damped = true) { + double lambda_ = damped ? 0.2 : 0.0; + + Eigen::JacobiSVD<Eigen::MatrixXd> svd(M_, Eigen::ComputeFullU | Eigen::ComputeFullV); + Eigen::JacobiSVD<Eigen::MatrixXd>::SingularValuesType sing_vals_ = svd.singularValues(); + Eigen::MatrixXd S_ = M_; // copying the dimensions of M_, its content is not needed. + S_.setZero(); + + for (int i = 0; i < sing_vals_.size(); i++) + S_(i, i) = (sing_vals_(i)) / (sing_vals_(i) * sing_vals_(i) + lambda_ * lambda_); + + M_pinv_ = Eigen::MatrixXd(svd.matrixV() * S_.transpose() * svd.matrixU().transpose()); +} + +} // namespace franka_example_controllers diff --git a/fr3_impedance_controller_real/launch/cartesian_impedance_example_controller.launch b/fr3_impedance_controller_real/launch/cartesian_impedance_example_controller.launch index 682f04cfcd180840857522b592d624f7b1c2eae4..c62f6e71d5dabaffcefc2269b335461bcbd0464b 100644 --- a/fr3_impedance_controller_real/launch/cartesian_impedance_example_controller.launch +++ b/fr3_impedance_controller_real/launch/cartesian_impedance_example_controller.launch @@ -1,20 +1,20 @@ <?xml version="1.0" ?> <launch> - <arg name="robot" default="panda" doc="choose your robot. Possible values: [panda, fr3]"/> + <arg name="robot" default="fr3" doc="choose your robot. Possible values: [panda, fr3]"/> <arg name="arm_id" default="$(arg robot)" /> <arg name="linear_gain" default="1.0" /> <arg name="angular_gain" default="1.0" /> <include file="$(find franka_control)/launch/franka_control.launch" pass_all_args="true"/> - <include file="$(find spacenav_node)/launch/classic.launch" pass_all_args="true"/> + <!-- <include file="$(find spacenav_node)/launch/classic.launch" pass_all_args="true"/> --> <rosparam command="load" file="$(find franka_example_controllers)/config/franka_example_controllers.yaml" subst_value="true" /> <node name="controller_spawner" pkg="controller_manager" type="spawner" respawn="false" output="screen" args="cartesian_impedance_example_controller"/> - <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/franka_description_with_marker.rviz"/> - <node name="interactive_marker" pkg="franka_example_controllers" type="interactive_marker.py" required="true" output="screen"> + <!-- <node pkg="rviz" type="rviz" output="screen" name="rviz" args="-d $(find franka_example_controllers)/launch/rviz/franka_description_with_marker.rviz"/> --> + <!-- <node name="interactive_marker" pkg="franka_example_controllers" type="interactive_marker.py" required="true" output="screen"> <param name="link_name" value="$(arg arm_id)_link0" /> <remap from="equilibrium_pose" to="/cartesian_impedance_example_controller/equilibrium_pose" /> - </node> + </node> --> <node name="rqt_reconfigure" pkg="rqt_reconfigure" type="rqt_reconfigure" required="false" /> </launch> diff --git a/fr3_impedance_controller_real/package.xml b/fr3_impedance_controller_real/package.xml index 297f2003c5617cd900dc32956aec47fee2b122c8..8530cf3f9da06361fbc5f890784d86356471bfe3 100644 --- a/fr3_impedance_controller_real/package.xml +++ b/fr3_impedance_controller_real/package.xml @@ -1,11 +1,15 @@ <?xml version="1.0"?> <package format="2"> - <name>fr3_impedance_controller_real</name> - <version>0.0.1</version> - <description>Impedance controller for the Franka Emika FR3</description> - <maintainer email="todo@todo.com"></maintainer> + <name>franka_example_controllers</name> + <version>0.10.1</version> + <description>franka_example_controllers provides example code for controlling Franka Emika research robots with ros_control</description> + <maintainer email="support@franka.de">Franka Emika GmbH</maintainer> <license>Apache 2.0</license> + <url type="website">http://wiki.ros.org/franka_example_controllers</url> + <url type="repository">https://github.com/frankaemika/franka_ros</url> + <url type="bugtracker">https://github.com/frankaemika/franka_ros/issues</url> + <author>Franka Emika GmbH</author> <buildtool_depend>catkin</buildtool_depend> @@ -19,7 +23,6 @@ <depend>eigen_conversions</depend> <depend>franka_hw</depend> <depend>franka_gripper</depend> - <depend>franka_example_controllers</depend> <depend>geometry_msgs</depend> <depend>hardware_interface</depend> <depend>joint_limits_interface</depend> @@ -30,7 +33,6 @@ <depend>realtime_tools</depend> <depend>roscpp</depend> <depend>urdf</depend> - <depend>sensor_msgs</depend> <depend>visualization_msgs</depend> <exec_depend>franka_control</exec_depend> @@ -39,6 +41,6 @@ <exec_depend>rospy</exec_depend> <export> - <controller_interface plugin="${prefix}/fr3_impedance_controller_real_plugin.xml" /> + <controller_interface plugin="${prefix}/franka_example_controllers_plugin.xml" /> </export> </package> diff --git a/fr3_impedance_controller_real/src/cartesian_impedance_example_controller.cpp b/fr3_impedance_controller_real/src/cartesian_impedance_example_controller.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59dc9f652ff84164c8d71856a1bee76e010dd44a --- /dev/null +++ b/fr3_impedance_controller_real/src/cartesian_impedance_example_controller.cpp @@ -0,0 +1,620 @@ +// Copyright (c) 2017 Franka Emika GmbH +// Use of this source code is governed by the Apache-2.0 license, see LICENSE +#include <franka_example_controllers/cartesian_impedance_example_controller.h> + +#include <cmath> +#include <iomanip> +#include <memory> + +#include <controller_interface/controller_base.h> +#include <franka/robot_state.h> +#include <pluginlib/class_list_macros.h> +#include <ros/ros.h> + +#include <franka_example_controllers/pseudo_inversion.h> + +/* Custom libraries */ +#include "orientation_utilities.hpp" +#include "robotics_utilities.hpp" + +namespace pin = pinocchio; +namespace ori = orient_utils; +namespace robo = robot_utils; + +using namespace std; +// using pin::ReferenceFrame; + +namespace franka_example_controllers +{ +bool CartesianImpedanceExampleController::init(hardware_interface::RobotHW * robot_hw, + ros::NodeHandle & node_handle) +{ + //* Load URDF model and data *// + if (urdf_filename_.empty()) + { + throw std::runtime_error("URDF filename is invalid"); + } + pin::urdf::buildModel(urdf_filename_, model_); + data_ = pin::Data(model_); + ee_id_ = model_.getFrameId("fr3_hand_tcp", (pin::FrameType::BODY)); + + //* Set Publisher *// + pub_ctrl_state_ = node_handle.advertise<fr3_custom_msgs::ControllerState>("controller_state", 20); + + //* Set Subscriber *// + // NOTE: you need to change topic name as `/spacenav/joy` if you want to command gripper + sub_joy_ = node_handle.subscribe<sensor_msgs::Joy>( + "/joy", 1, &CartesianImpedanceExampleController::subscribe_joy_command, this); + + // FIXME: spacenav is not operating !! + // sub_target_twist_ = node_handle.subscribe<geometry_msgs::Twist>( + // "/spacenav/twist", 1, &CartesianImpedanceExampleController::subscribe_target_twist, this); + + //* Set HW interface *// + std::string arm_id; + if (!node_handle.getParam("arm_id", arm_id)) + { + ROS_ERROR_STREAM("CartesianImpedanceExampleController: Could not read parameter arm_id"); + return false; + } + std::vector<std::string> joint_names; + if (!node_handle.getParam("joint_names", joint_names) || joint_names.size() != 7) + { + ROS_ERROR( + "CartesianImpedanceExampleController: Invalid or no joint_names parameters provided, " + "aborting controller init!"); + return false; + } + + auto * model_interface = robot_hw->get<franka_hw::FrankaModelInterface>(); + if (model_interface == nullptr) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Error getting model interface from hardware"); + return false; + } + try + { + model_handle_ = + std::make_unique<franka_hw::FrankaModelHandle>(model_interface->getHandle(arm_id + "_model")); + } + catch (hardware_interface::HardwareInterfaceException & ex) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Exception getting model handle from interface: " + << ex.what()); + return false; + } + + auto * state_interface = robot_hw->get<franka_hw::FrankaStateInterface>(); + if (state_interface == nullptr) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Error getting state interface from hardware"); + return false; + } + try + { + state_handle_ = + std::make_unique<franka_hw::FrankaStateHandle>(state_interface->getHandle(arm_id + "_robot")); + } + catch (hardware_interface::HardwareInterfaceException & ex) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Exception getting state handle from interface: " + << ex.what()); + return false; + } + + auto * effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); + if (effort_joint_interface == nullptr) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Error getting effort joint interface from hardware"); + return false; + } + for (size_t i = 0; i < 7; ++i) + { + try + { + joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i])); + } + catch (const hardware_interface::HardwareInterfaceException & ex) + { + ROS_ERROR_STREAM( + "CartesianImpedanceExampleController: Exception getting joint handles: " << ex.what()); + return false; + } + } + + //* Initialize states *// + this->init_states(); // NOTE: this should be executed aforehand of parameter callback + + //* Parameter server declaration *// + ctrl_param_node_ = ros::NodeHandle(node_handle.getNamespace() + "/controller_param_node"); + + ctrl_param_server_ = std::make_unique< + dynamic_reconfigure::Server<franka_example_controllers::controller_paramConfig>>( + ctrl_param_node_); + + ctrl_param_server_->setCallback( + boost::bind(&CartesianImpedanceExampleController::request_controller_parameters, this, _1, _2)); + + //* Create controllers *// + imp_ = std::make_unique<ImpedanceController<double>>(); + dob_ = std::make_unique<DisturbanceObserver<double>>(fq_); + mob_ = std::make_unique<MomentumObserver<double>>(r_th_, km_); + sosml_ = std::make_unique<SlidingModeObserver<double>>(s1_, s2_, t1_, t2_); + + return true; +} + +void CartesianImpedanceExampleController::starting(const ros::Time & /*time*/) +{ + // compute initial velocity with jacobian and set x_attractor + franka::RobotState initial_state = state_handle_->getRobotState(); + Eigen::Map<Vec7<double>> q_init(initial_state.q.data()); + Eigen::Affine3d initial_transform(Eigen::Matrix4d::Map(initial_state.O_T_EE.data())); + + /* set equilibrium pose to current state */ + ee_pos_world_des_ = initial_transform.translation(); + ee_quat_world_des_ = Eigen::Quaterniond(initial_transform.rotation()); + + /* set nullspace equilibrium configuration to initial q */ + q_null_des_ = q_init; +} + +void CartesianImpedanceExampleController::update(const ros::Time & /*time*/, + const ros::Duration & period) +{ + if (b_count_loop_time_ == true) + { + loop_timer_.start(); + } + // cout << std::fixed; + // cout << std::setprecision(5); + // TODO: add safety logic for time derivative when dt is very small + // double dt = period.toSec(); // timestep + double dt = 0.001; + + //* ----- set Desired EE Pose & Twist ------------------------------------------------------------ + // TODO: Add safety for FR3 end-effector's vel, acc, jerk limits + Vec3<double> v_des = ee_vel_world_des_.head(3); + Vec3<double> w_des = ee_vel_world_des_.tail(3); + ee_pos_world_des_ += v_des * dt; + ee_quat_world_des_ = ori::getNewQuat(ee_quat_world_des_, w_des, dt); + // ee_rpy_world_des_ = ori::quaternionToRPY(ee_quat_world_des_, ee_rpy_world_des_prev_); + + //* ----- get Current States -------------------------------------------------------------------- + franka::RobotState robot_state = state_handle_->getRobotState(); + Eigen::Map<Vec7<double>> tau_J_d(robot_state.tau_J_d.data()); // NOLINT + Eigen::Map<const Vec6<double>> tau_ext_hat_filtered(robot_state.tau_ext_hat_filtered.data()); + q_mes_ = Eigen::Map<const Vec7<double>>(robot_state.q.data()); + dq_mes_ = Eigen::Map<const Vec7<double>>(robot_state.dq.data()); + + // TODO: check noise level + // ddq_eul_ = robo::getEulerDerivative(dq_mes_, dq_mes_prev_, dt); + ddq_eul_ = robo::getFilteredEulerDerivative(dq_mes_, dq_mes_prev_, ddq_eul_prev_, dt, 10.0); + + pin::forwardKinematics(model_, data_, q_mes_, dq_mes_); + pin::updateFramePlacements(model_, data_); + + ee_pos_world_mes_ = data_.oMf[ee_id_].translation(); + RotMat<double> R_OE = data_.oMf[ee_id_].rotation(); + ee_quat_world_mes_ = Quat<double>(R_OE); + // ee_rpy_world_mes_ = ori::quaternionToRPY(ee_quat_world_mes_, ee_rpy_world_mes_prev_); + + //* ----- compute Kinematics & Dynamics ---------------------------------------------------------- + /* Jacobian */ + Mat67<double> Je, dJe; + pin::getFrameJacobian(model_, data_, ee_id_, pin::ReferenceFrame::LOCAL_WORLD_ALIGNED, Je); + pin::getFrameJacobianTimeVariation(model_, data_, ee_id_, + pin::ReferenceFrame::LOCAL_WORLD_ALIGNED, dJe); + + Mat76<double> Je_t = Je.transpose(); + MatX<double> Je_pinv, Je_t_pinv; + pseudoInverse(Je, Je_pinv); + pseudoInverse(Je_t, Je_t_pinv); + // NOTE: using `pseudoInverse()` might be more safe against singularities + // MatX<double> Je_pinv = Je.completeOrthogonalDecomposition().pseudoInverse(); + // MatX<double> Je_t_pinv = Je.transpose().completeOrthogonalDecomposition().pseudoInverse(); + + /* compute current EE Twist & Acceleration using backward Euler method */ + ee_vel_world_mes_ = Je * dq_mes_; + // ee_acc_world_eul_ = robo::getEulerDerivative(ee_vel_world_mes_, ee_vel_world_mes_prev_, dt); + ee_acc_world_eul_ = robo::getFilteredEulerDerivative(ee_vel_world_mes_, ee_vel_world_mes_prev_, ee_acc_world_eul_prev_, dt, 10.0); + + /* Inertia matrix */ + pin::crba(model_, data_, q_mes_); + // Mat7<double> M = data_.M; // upper triangular matrix in joint-space + // Vec7<double> k_mass; + // k_mass << 1.0, 1.0, 1.0, 1.0, 10.0, 10.0, 50.0; + // M.diagonal().array() *= k_mass.array(); + Mat7<double> M = robo::computeFullInertiaMatrix(data_.M); + Mat6<double> Me = robo::computeTaskInertiaMatrix(M, Je_pinv, Je_t_pinv); + + /* Coriolis, Centrifugal & Gravity torque */ + pin::computeCoriolisMatrix(model_, data_, q_mes_, dq_mes_); + Mat7<double> C = data_.C; + Vec7<double> tau_c = C * dq_mes_; + + // pin::computeGeneralizedGravity(model_, data_, q_mes_); // * gravity is compensated internally + // Vec7<double> tau_g = data_.g; + Vec7<double> tau_g; + tau_g.setZero(); + + //* ----- CONTROL LAW ---------------------------------------------------------------------------- + /* Cartesian impedance control */ + imp_->set_parameters(K_task_, D_task_, K_null_, D_null_); + Vec6<double> ee_pose_err = imp_->get_pose_error(ee_pos_world_des_, ee_pos_world_mes_, + ee_quat_world_des_, ee_quat_world_mes_); + Vec6<double> ee_pose_err_prev = imp_->get_previous_pose_error(); + Vec6<double> dpose_err = robo::getEulerDerivative(ee_pose_err, ee_pose_err_prev, dt); + Vec6<double> F_task = imp_->get_task_impedance_force(dpose_err); + + /* Task-Force Disturbance compensation */ + Vec7<double> tau_task = Je_t * (F_task - (b_dob_applied_ ? Fd_hat_dob_ : Vec6<double>::Zero())); + + /* Null-space impedance control */ + imp_->compute_null_error(q_null_des_, q_mes_); + Vec7<double> tau_null = imp_->get_null_impedance_torque(dq_mes_, Je_t, Je_t_pinv); + + /* compute desired joint torque command */ + Vec7<double> tau_des = tau_task + tau_null + tau_c; + tau_des << saturateTorqueRate(tau_des, tau_J_d); // Saturate torque rate to avoid discontinuities + + //* ----- Observers ------------------------------------------------------------------------------ + Fd_hat_fr_ = Je_t_pinv * tau_ext_hat_filtered; + + /* Momentum Observer (MOB) */ + h_mes_ = M * dq_mes_; + Vec7<double> dh_mes = robo::getEulerDerivative(h_mes_, h_mes_prev_, dt); + + mob_->set_parameters(dt, r_th_, km_); // TODO: set parameter similar level to DOB for comparison + mob_->set_dynamics(tau_des, M, C, tau_g); + mob_->compute_residual(dh_mes, dq_mes_); + + ddq_hat_mob_ = mob_->get_joint_accel_estimation(dq_mes_); + ee_acc_world_hat_mob_ = robo::getTaskAcceleration(Je, dJe, dq_mes_, ddq_hat_mob_); + tau_d_hat_mob_ = mob_->get_external_torque_estimation(); + Fd_hat_mob_ = Je_t_pinv * tau_d_hat_mob_; + + /* 2nd-order Sliding mode Observer (SOSML) */ + sosml_->set_parameters(dt, s1_, s2_, t1_, t2_); + sosml_->set_dynamics(tau_des, M, C, tau_g); + sosml_->compute_momentum_estimation(dq_mes_); + ddq_hat_sosml_ = sosml_->get_joint_accel_estimation(); + ee_acc_world_hat_sosml_ = robo::getTaskAcceleration(Je, dJe, dq_mes_, ddq_hat_sosml_); + tau_d_hat_sosml_ = sosml_->get_external_torque_estimation(); + Fd_hat_sosml_ = Je_t_pinv * tau_d_hat_sosml_; + + /* Task-space Force Disturbance Observer (TFDOB) */ + dob_->set_parameters(dt, fq_); + Vec6<double> ddx = (b_sosml_applied_ ? ee_acc_world_hat_sosml_ : ee_acc_world_eul_); + Fd_hat_dob_ = dob_->get_force_disturbance(F_task, Me, ddx); + tau_d_hat_dob_ = Je_t * Fd_hat_dob_; + + //* send joint torque command *// + for (size_t i = 0; i < 7; ++i) + { + joint_handles_[i].setCommand(tau_des(i)); + } + this->publish_controller_state(); // publish states for rosbag + + //* update previous states *// + this->update_previous_states(); + imp_->update_previous_states(); + dob_->update_previous_states(); + + //* update parameters online either via dynamic reconfigure or target by filtering *// + /* update desired twist via joystick */ + ee_vel_world_des_ = alpha_ * ee_vel_world_target_ + (1.0 - alpha_) * ee_vel_world_des_; + + /* update controller parameters */ + K_task_ = alpha_ * K_task_target_ + (1.0 - alpha_) * K_task_; + D_task_ = alpha_ * D_task_target_ + (1.0 - alpha_) * D_task_; + K_null_ = alpha_ * K_null_target_ + (1.0 - alpha_) * K_null_; + D_null_ = alpha_ * D_null_target_ + (1.0 - alpha_) * D_null_; + + fq_ = alpha_ * fq_target_ + (1.0 - alpha_) * fq_; + s1_ = alpha_ * s1_target_ + (1.0 - alpha_) * s1_; + s2_ = alpha_ * s2_target_ + (1.0 - alpha_) * s2_; + t1_ = s1_.array().sqrt(); + t2_ = s2_.array().sqrt(); + r_th_ = alpha_ * r_th_target_ + (1.0 - alpha_) * r_th_; + km_ = alpha_ * km_target_ + (1.0 - alpha_) * km_; + + if(b_count_loop_time_ == true) + { + if(max_exec_time_ < loop_timer_.getMillisec()) + { + max_exec_time_ = loop_timer_.getMillisec(); + } + cout << "[Execution time] " << loop_timer_.getMillisec() << "(msec) [Max] " << max_exec_time_ << endl; + } +} + +//* ----- SUBSCRIBE CALLBACK ----------------------------------------------------------------------- +void CartesianImpedanceExampleController::subscribe_target_twist( + const geometry_msgs::TwistConstPtr & msg) +{ + // cout << msg->linear.x << ", " << msg->linear.y << ", " << msg->linear.z << endl; + ee_vel_world_des_[0] = twist_scale_[0] * msg->linear.x; + ee_vel_world_des_[1] = twist_scale_[1] * msg->linear.y; + ee_vel_world_des_[2] = twist_scale_[2] * msg->linear.z; + ee_vel_world_des_[3] = twist_scale_[3] * msg->angular.x; + ee_vel_world_des_[4] = twist_scale_[4] * msg->angular.y; + ee_vel_world_des_[5] = twist_scale_[5] * msg->angular.z; +} + +void CartesianImpedanceExampleController::subscribe_joy_command( + const sensor_msgs::JoyConstPtr & msg) +{ + // btn_cmd_[0] = msg->buttons[0]; + // btn_cmd_[1] = msg->buttons[1]; + + ee_vel_world_target_[0] = static_cast<double>(twist_scale_[0] * msg->axes[0]); // x + ee_vel_world_target_[1] = static_cast<double>(twist_scale_[1] * msg->axes[1]); // y + ee_vel_world_target_[2] = static_cast<double>(twist_scale_[2] * msg->axes[5]); // z + ee_vel_world_target_[3] = static_cast<double>(twist_scale_[3] * msg->axes[2]); // roll + ee_vel_world_target_[4] = static_cast<double>(twist_scale_[4] * msg->axes[3]); // pitch + ee_vel_world_target_[5] = static_cast<double>(twist_scale_[5] * msg->axes[4]); // yaw +} + +//* ----- PARAMETER SERVER CALLBACK ---------------------------------------------------------------- +void CartesianImpedanceExampleController::request_controller_parameters( + franka_example_controllers::controller_paramConfig & config, uint32_t /*level*/) +{ + //* Impedance Controller (NOTE: Damping ratio = 1) *// + /* task-space PD gains */ + K_task_target_.setIdentity().diagonal() << config.K_task_x, config.K_task_y, config.K_task_z, // + config.K_task_rot, config.K_task_rot, config.K_task_rot; + D_task_target_.setIdentity().diagonal() << 2.0 * K_task_target_.diagonal().array().sqrt(); + + /* null-space PD gains */ + K_null_target_.setIdentity().diagonal() << config.K_null, config.K_null, config.K_null, // + config.K_null, config.K_null, config.K_null, config.K_null; + D_null_target_.setIdentity().diagonal() << 2.0 * K_null_target_.diagonal().array().sqrt(); + + //* Disturbance Observer *// + fq_target_ << config.fq, config.fq, config.fq, config.fq, config.fq, config.fq; + + //* Sliding Mode Observer *// + s1_target_ << config.s1, config.s1, config.s1, config.s1, config.s1, config.s1, config.s1; + s2_target_ << config.s2, config.s2, config.s2, config.s2, config.s2, config.s2, config.s2; + + //* Momentum Observer *// + r_th_target_ << config.r_th, config.r_th, config.r_th, config.r_th, config.r_th, config.r_th, + config.r_th; + km_target_ << config.Km, config.Km, config.Km, config.Km, config.Km, config.Km, config.Km; +} + +//* ----- METHODS ---------------------------------------------------------------------------------- +void CartesianImpedanceExampleController::init_states() +{ + //* subscriber *// + ee_vel_world_target_.setZero(); + + //* control parameters *// + /* impedance */ + K_task_.setIdentity().diagonal() << 200.0, 200.0, 200.0, 10.0, 10.0, 10.0; // TODO: set default + K_task_target_.setIdentity(); + D_task_.setIdentity().diagonal() << 2.0 * K_task_.diagonal().array().sqrt(); + D_task_target_.setIdentity(); + K_null_.setIdentity().diagonal() << 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5; + K_null_target_.setIdentity(); + D_null_.setIdentity().diagonal() << 2.0 * K_null_.diagonal().array().sqrt(); + D_null_target_.setIdentity(); + + /* DOB */ + fq_ << 15.0, 15.0, 15.0, 15.0, 15.0, 15.0; + fq_target_.setZero(); + + /* SOSML */ + s1_ << 10, 10, 10, 10, 10, 10, 10; + s1_target_.setZero(); + s2_ << 200, 200, 200, 200, 200, 200, 200; + s2_target_.setZero(); + t1_ = s1_.array().sqrt(); + t1_target_.setZero(); + t2_ = s2_.array().sqrt(); + t2_target_.setZero(); + + /* MOB */ + r_th_ << 0, 0, 0, 0, 0, 0, 0; + r_th_target_.setZero(); + km_ << 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5; + km_target_.setZero(); + + //* Control states *// + q_mes_.setZero(); + dq_mes_.setZero(); + dq_mes_prev_.setZero(); + ddq_eul_.setZero(); + ddq_eul_prev_.setZero(); + q_null_des_.setZero(); + + ee_pos_world_des_.setZero(); + ee_quat_world_des_.coeffs() << 0.0, 0.0, 0.0, 1.0; + ee_rpy_world_des_.setZero(); + ee_rpy_world_des_prev_.setZero(); + ee_vel_world_des_.setZero(); + ee_vel_world_des_prev_.setZero(); + ee_acc_world_des_.setZero(); + ee_acc_world_des_prev_.setZero(); + + ee_pos_world_mes_.setZero(); + ee_quat_world_mes_.coeffs() << 0.0, 0.0, 0.0, 1.0; + ee_rpy_world_mes_.setZero(); + ee_rpy_world_mes_prev_.setZero(); + ee_vel_world_mes_.setZero(); + ee_vel_world_mes_prev_.setZero(); + ee_acc_world_eul_.setZero(); + ee_acc_world_eul_prev_.setZero(); + + tau_d_hat_dob_.setZero(); + Fd_hat_dob_.setZero(); + + ddq_hat_sosml_.setZero(); + tau_d_hat_sosml_.setZero(); + ee_acc_world_hat_sosml_.setZero(); + Fd_hat_sosml_.setZero(); + + h_mes_.setZero(); + h_mes_prev_.setZero(); + ddq_hat_mob_.setZero(); + ee_acc_world_hat_mob_.setZero(); + tau_d_hat_mob_.setZero(); + Fd_hat_mob_.setZero(); + + Fd_hat_fr_.setZero(); +} + +void CartesianImpedanceExampleController::publish_controller_state() +{ + for (int i = 0; i < 7; ++i) + { + msg_ctrl_state_.ddq_eul[i] = ddq_eul_[i]; + msg_ctrl_state_.ddq_mob[i] = ddq_hat_mob_[i]; + msg_ctrl_state_.ddq_sosml[i] = ddq_hat_sosml_[i]; + + msg_ctrl_state_.tau_dist_dob[i] = tau_d_hat_dob_[i]; + msg_ctrl_state_.tau_dist_mob[i] = tau_d_hat_mob_[i]; + msg_ctrl_state_.tau_dist_sosml[i] = tau_d_hat_sosml_[i]; + } + + msg_ctrl_state_.F_dist_franka.force.x = Fd_hat_fr_[0]; + msg_ctrl_state_.F_dist_franka.force.y = Fd_hat_fr_[1]; + msg_ctrl_state_.F_dist_franka.force.z = Fd_hat_fr_[2]; + msg_ctrl_state_.F_dist_franka.torque.x = Fd_hat_fr_[3]; + msg_ctrl_state_.F_dist_franka.torque.y = Fd_hat_fr_[4]; + msg_ctrl_state_.F_dist_franka.torque.z = Fd_hat_fr_[5]; + + msg_ctrl_state_.F_dist_dob.force.x = Fd_hat_dob_[0]; + msg_ctrl_state_.F_dist_dob.force.y = Fd_hat_dob_[1]; + msg_ctrl_state_.F_dist_dob.force.z = Fd_hat_dob_[2]; + msg_ctrl_state_.F_dist_dob.torque.x = Fd_hat_dob_[3]; + msg_ctrl_state_.F_dist_dob.torque.y = Fd_hat_dob_[4]; + msg_ctrl_state_.F_dist_dob.torque.z = Fd_hat_dob_[5]; + + msg_ctrl_state_.F_dist_mob.force.x = Fd_hat_mob_[0]; + msg_ctrl_state_.F_dist_mob.force.y = Fd_hat_mob_[1]; + msg_ctrl_state_.F_dist_mob.force.z = Fd_hat_mob_[2]; + msg_ctrl_state_.F_dist_mob.torque.x = Fd_hat_mob_[3]; + msg_ctrl_state_.F_dist_mob.torque.y = Fd_hat_mob_[4]; + msg_ctrl_state_.F_dist_mob.torque.z = Fd_hat_mob_[5]; + + /* task-space pose */ + msg_ctrl_state_.ee_pose_world_des.position.x = ee_pos_world_des_[0]; + msg_ctrl_state_.ee_pose_world_des.position.y = ee_pos_world_des_[1]; + msg_ctrl_state_.ee_pose_world_des.position.z = ee_pos_world_des_[2]; + msg_ctrl_state_.ee_pose_world_des.orientation.x = ee_quat_world_des_.x(); + msg_ctrl_state_.ee_pose_world_des.orientation.y = ee_quat_world_des_.y(); + msg_ctrl_state_.ee_pose_world_des.orientation.z = ee_quat_world_des_.z(); + msg_ctrl_state_.ee_pose_world_des.orientation.w = ee_quat_world_des_.w(); + + msg_ctrl_state_.ee_pose_world_mes.position.x = ee_pos_world_mes_[0]; + msg_ctrl_state_.ee_pose_world_mes.position.y = ee_pos_world_mes_[1]; + msg_ctrl_state_.ee_pose_world_mes.position.z = ee_pos_world_mes_[2]; + msg_ctrl_state_.ee_pose_world_mes.orientation.x = ee_quat_world_mes_.x(); + msg_ctrl_state_.ee_pose_world_mes.orientation.y = ee_quat_world_mes_.y(); + msg_ctrl_state_.ee_pose_world_mes.orientation.z = ee_quat_world_mes_.z(); + msg_ctrl_state_.ee_pose_world_mes.orientation.w = ee_quat_world_mes_.w(); + + /* task-space twist */ + msg_ctrl_state_.ee_vel_world_des.linear.x = ee_vel_world_des_[0]; + msg_ctrl_state_.ee_vel_world_des.linear.y = ee_vel_world_des_[1]; + msg_ctrl_state_.ee_vel_world_des.linear.z = ee_vel_world_des_[2]; + msg_ctrl_state_.ee_vel_world_des.angular.x = ee_vel_world_des_[3]; + msg_ctrl_state_.ee_vel_world_des.angular.y = ee_vel_world_des_[4]; + msg_ctrl_state_.ee_vel_world_des.angular.z = ee_vel_world_des_[5]; + + msg_ctrl_state_.ee_vel_world_mes.linear.x = ee_vel_world_mes_[0]; + msg_ctrl_state_.ee_vel_world_mes.linear.y = ee_vel_world_mes_[1]; + msg_ctrl_state_.ee_vel_world_mes.linear.z = ee_vel_world_mes_[2]; + msg_ctrl_state_.ee_vel_world_mes.angular.x = ee_vel_world_mes_[3]; + msg_ctrl_state_.ee_vel_world_mes.angular.y = ee_vel_world_mes_[4]; + msg_ctrl_state_.ee_vel_world_mes.angular.z = ee_vel_world_mes_[5]; + + /* task-space acceleration */ + msg_ctrl_state_.ee_acc_world_eul.linear.x = ee_acc_world_eul_[0]; + msg_ctrl_state_.ee_acc_world_eul.linear.y = ee_acc_world_eul_[1]; + msg_ctrl_state_.ee_acc_world_eul.linear.z = ee_acc_world_eul_[2]; + msg_ctrl_state_.ee_acc_world_eul.angular.x = ee_acc_world_eul_[3]; + msg_ctrl_state_.ee_acc_world_eul.angular.y = ee_acc_world_eul_[4]; + msg_ctrl_state_.ee_acc_world_eul.angular.z = ee_acc_world_eul_[5]; + + msg_ctrl_state_.ee_acc_world_mob.linear.x = ee_acc_world_hat_mob_[0]; + msg_ctrl_state_.ee_acc_world_mob.linear.y = ee_acc_world_hat_mob_[1]; + msg_ctrl_state_.ee_acc_world_mob.linear.z = ee_acc_world_hat_mob_[2]; + msg_ctrl_state_.ee_acc_world_mob.angular.x = ee_acc_world_hat_mob_[3]; + msg_ctrl_state_.ee_acc_world_mob.angular.y = ee_acc_world_hat_mob_[4]; + msg_ctrl_state_.ee_acc_world_mob.angular.z = ee_acc_world_hat_mob_[5]; + + msg_ctrl_state_.ee_acc_world_sosml.linear.x = ee_acc_world_hat_sosml_[0]; + msg_ctrl_state_.ee_acc_world_sosml.linear.y = ee_acc_world_hat_sosml_[1]; + msg_ctrl_state_.ee_acc_world_sosml.linear.z = ee_acc_world_hat_sosml_[2]; + msg_ctrl_state_.ee_acc_world_sosml.angular.x = ee_acc_world_hat_sosml_[3]; + msg_ctrl_state_.ee_acc_world_sosml.angular.y = ee_acc_world_hat_sosml_[4]; + msg_ctrl_state_.ee_acc_world_sosml.angular.z = ee_acc_world_hat_sosml_[5]; + + pub_ctrl_state_.publish(msg_ctrl_state_); +} + +void CartesianImpedanceExampleController::update_previous_states() +{ + dq_mes_prev_ = dq_mes_; + ddq_eul_prev_ = ddq_eul_; + ee_rpy_world_des_prev_ = ee_rpy_world_des_; + ee_vel_world_des_prev_ = ee_vel_world_des_; + ee_acc_world_des_prev_ = ee_acc_world_des_; + ee_rpy_world_mes_prev_ = ee_rpy_world_mes_; + ee_vel_world_mes_prev_ = ee_vel_world_mes_; + ee_acc_world_eul_prev_ = ee_acc_world_eul_; + + h_mes_prev_ = h_mes_; +} + +Eigen::Matrix<double, 7, 1> CartesianImpedanceExampleController::saturateTorqueRate( + const Eigen::Matrix<double, 7, 1> & tau_d_calculated, const Eigen::Matrix<double, 7, 1> & tau_J_d) +{ // NOLINT (readability-identifier-naming) + Eigen::Matrix<double, 7, 1> tau_d_saturated{}; + for (size_t i = 0; i < 7; i++) + { + double difference = tau_d_calculated[i] - tau_J_d[i]; + tau_d_saturated[i] = + tau_J_d[i] + std::max(std::min(difference, delta_tau_max_), -delta_tau_max_); + } + return tau_d_saturated; +} + +//* ----- PRINTER ---------------------------------------------------------------------------------- +void CartesianImpedanceExampleController::print_end_effector_states() +{ + // cout << "Target EE twist:\t" << ee_vel_world_target_.transpose() << endl; + // cout << "Desired EE twist:\t" << ee_vel_world_des_.transpose() << endl; + // std::cout << "Desired EE pos [m]:\t" << ee_pos_world_des_.transpose() << std::endl; + // std::cout << "Desired EE RPY [rad]:\t" << ee_rpy_world_des_.transpose() << std::endl; + cout << "Desired EE pos [m]:\t" << ee_pos_world_des_.transpose() << endl; + cout << "Desired EE RPY [rad]:\t" << ee_rpy_world_des_.transpose() << endl; + cout << "Measured EE RPY [rad]:\t" << ee_rpy_world_mes_.transpose() << endl << endl; + // NOTE: results from FR3 state & pinocchio are almost the same. + // cout << "Measured Pin EE pos [m]:\t" << ee_pos_world_mes_.transpose() << endl; + // cout << "Measured FR3 EE pos [m]:\t" << position.transpose() << endl; + // cout << "Measured Pin EE quat:\t" << ee_quat_world_mes_ << endl; + // cout << "Measured FR3 EE quat:\t" << orientation << endl; +} + +void CartesianImpedanceExampleController::print_dynamics() +{ + // NOTE: dynamics are a little bit different + // cout << "FR3:\n" << M_fr << endl; + // cout << "Pin:\n" << M << endl; + // cout << "Coriolis FR3:\t" << coriolis.transpose() << endl; + // cout << "Coriolis Pin:\t" << tau_c.transpose() << endl; +} + +} // namespace franka_example_controllers + +PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianImpedanceExampleController, + controller_interface::ControllerBase) diff --git a/fr3_impedance_controller_real/src/fr3_impedance_controller_real.cpp b/fr3_impedance_controller_real/src/fr3_impedance_controller_real.cpp deleted file mode 100644 index e7798abde6b77b30ad58cf259a7af0f5293b60d6..0000000000000000000000000000000000000000 --- a/fr3_impedance_controller_real/src/fr3_impedance_controller_real.cpp +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (c) 2017 Franka Emika GmbH -// Use of this source code is governed by the Apache-2.0 license, see LICENSE -#include <franka_example_controllers/cartesian_impedance_example_controller.h> - -#include <cmath> -#include <iomanip> -#include <memory> - -#include <controller_interface/controller_base.h> -#include <franka/robot_state.h> -#include <pluginlib/class_list_macros.h> -#include <ros/ros.h> - -#include <franka_example_controllers/pseudo_inversion.h> - -namespace franka_example_controllers -{ -bool CartesianImpedanceExampleController::init(hardware_interface::RobotHW * robot_hw, - ros::NodeHandle & node_handle) -{ - std::vector<double> cartesian_stiffness_vector; - std::vector<double> cartesian_damping_vector; - - /* Subscriber declaration */ - sub_equilibrium_pose_ = node_handle.subscribe( - "equilibrium_pose", 20, &CartesianImpedanceExampleController::equilibriumPoseCallback, this, - ros::TransportHints().reliable().tcpNoDelay()); - - sub_target_twist_ = node_handle.subscribe<geometry_msgs::Twist>( - "/spacenav/twist", 1, &CartesianImpedanceExampleController::subscribe_target_twist, this); - - sub_joy_ = node_handle.subscribe<sensor_msgs::Joy>( - "/spacenave/joy", 1, &CartesianImpedanceExampleController::subscribe_joy_command, this); - - /* Initialize limits */ - fr3_vel_limit_ << 3.0, 3.0, 3.0, 2.5, 2.5, 2.5; // [m/s, rad/s] - fr3_acc_limit_ << 9.0, 9.0, 9.0, 17.0, 17.0, 17.0; // [m/s^2, rad/s^2] - fr3_jrk_limit_ << 4500.0, 4500.0, 4500.0, 8500.0, 8500.0, 8500.0; // [m/s^3, rad/s^3] - - std::string arm_id; - if (!node_handle.getParam("arm_id", arm_id)) - { - ROS_ERROR_STREAM("CartesianImpedanceExampleController: Could not read parameter arm_id"); - return false; - } - std::vector<std::string> joint_names; - if (!node_handle.getParam("joint_names", joint_names) || joint_names.size() != 7) - { - ROS_ERROR( - "CartesianImpedanceExampleController: Invalid or no joint_names parameters provided, " - "aborting controller init!"); - return false; - } - - auto * model_interface = robot_hw->get<franka_hw::FrankaModelInterface>(); - if (model_interface == nullptr) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Error getting model interface from hardware"); - return false; - } - try - { - model_handle_ = - std::make_unique<franka_hw::FrankaModelHandle>(model_interface->getHandle(arm_id + "_model")); - } - catch (hardware_interface::HardwareInterfaceException & ex) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Exception getting model handle from interface: " - << ex.what()); - return false; - } - - auto * state_interface = robot_hw->get<franka_hw::FrankaStateInterface>(); - if (state_interface == nullptr) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Error getting state interface from hardware"); - return false; - } - try - { - state_handle_ = - std::make_unique<franka_hw::FrankaStateHandle>(state_interface->getHandle(arm_id + "_robot")); - } - catch (hardware_interface::HardwareInterfaceException & ex) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Exception getting state handle from interface: " - << ex.what()); - return false; - } - - auto * effort_joint_interface = robot_hw->get<hardware_interface::EffortJointInterface>(); - if (effort_joint_interface == nullptr) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Error getting effort joint interface from hardware"); - return false; - } - for (size_t i = 0; i < 7; ++i) - { - try - { - joint_handles_.push_back(effort_joint_interface->getHandle(joint_names[i])); - } - catch (const hardware_interface::HardwareInterfaceException & ex) - { - ROS_ERROR_STREAM( - "CartesianImpedanceExampleController: Exception getting joint handles: " << ex.what()); - return false; - } - } - - dynamic_reconfigure_compliance_param_node_ = - ros::NodeHandle(node_handle.getNamespace() + "/dynamic_reconfigure_compliance_param_node"); - - dynamic_server_compliance_param_ = std::make_unique< - dynamic_reconfigure::Server<franka_example_controllers::compliance_paramConfig>>( - - dynamic_reconfigure_compliance_param_node_); - dynamic_server_compliance_param_->setCallback( - boost::bind(&CartesianImpedanceExampleController::complianceParamCallback, this, _1, _2)); - - /* Initialize states */ - ee_vel_scale_ << 0.1, 0.1, 0.1, 0.1, 0.1, 0.1; - ee_vel_world_des_.setZero(); - ee_vel_world_des_prev_.setZero(); - ee_acc_world_des_.setZero(); - ee_acc_world_des_prev_.setZero(); - ee_pos_world_des_.setZero(); - ee_quat_world_des_.coeffs() << 0.0, 0.0, 0.0, 1.0; - ee_rpy_world_des_.setZero(); - ee_rpy_world_des_prev_.setZero(); - ee_rpy_world_mes_.setZero(); - ee_rpy_world_mes_prev_.setZero(); - - position_d_.setZero(); - orientation_d_.coeffs() << 0.0, 0.0, 0.0, 1.0; - position_d_target_.setZero(); - orientation_d_target_.coeffs() << 0.0, 0.0, 0.0, 1.0; - - cartesian_stiffness_.setZero(); - cartesian_damping_.setZero(); - - return true; -} - -void CartesianImpedanceExampleController::starting(const ros::Time & /*time*/) -{ - // compute initial velocity with jacobian and set x_attractor and q_d_nullspace - // to initial configuration - franka::RobotState initial_state = state_handle_->getRobotState(); - // get jacobian - std::array<double, 42> jacobian_array = - model_handle_->getZeroJacobian(franka::Frame::kEndEffector); - // convert to eigen - Eigen::Map<Eigen::Matrix<double, 7, 1>> q_initial(initial_state.q.data()); - Eigen::Affine3d initial_transform(Eigen::Matrix4d::Map(initial_state.O_T_EE.data())); - - // set equilibrium point to current state - position_d_ = initial_transform.translation(); - orientation_d_ = Eigen::Quaterniond(initial_transform.rotation()); - position_d_target_ = initial_transform.translation(); - orientation_d_target_ = Eigen::Quaterniond(initial_transform.rotation()); - - ee_pos_world_des_ = initial_transform.translation(); - ee_quat_world_des_ = Eigen::Quaterniond(initial_transform.rotation()); - - // set nullspace equilibrium configuration to initial q - q_d_nullspace_ = q_initial; -} - -void CartesianImpedanceExampleController::update(const ros::Time & /*time*/, - const ros::Duration & period) -{ - /* get target end-effector's twist */ - // std::cout << std::fixed; - // std::cout << std::setprecision(5); - // std::cout << "Desired EE twist:\t" << ee_vel_world_des_.transpose() << std::endl; - - // TODO: Add safety for FR3 end-effector's vel, acc, jerk limits - - Vec3<double> v_des = ee_vel_world_des_.head(3); - Vec3<double> w_des = ee_vel_world_des_.tail(3); - ee_pos_world_des_ += v_des * period.toSec(); - ee_quat_world_des_ = orient_utils::getNewQuat(ee_quat_world_des_, w_des, period.toSec()); - ee_rpy_world_des_ = orient_utils::quaternionToRPY(ee_quat_world_des_, ee_rpy_world_des_prev_); - - // TODO: Add conversion of Quat2RPY to make debugging easier - - // get state variables - franka::RobotState robot_state = state_handle_->getRobotState(); - std::array<double, 7> coriolis_array = model_handle_->getCoriolis(); - std::array<double, 42> jacobian_array = - model_handle_->getZeroJacobian(franka::Frame::kEndEffector); - - // convert to Eigen - Eigen::Map<Eigen::Matrix<double, 7, 1>> coriolis(coriolis_array.data()); - Eigen::Map<Eigen::Matrix<double, 6, 7>> jacobian(jacobian_array.data()); - Eigen::Map<Eigen::Matrix<double, 7, 1>> q(robot_state.q.data()); - Eigen::Map<Eigen::Matrix<double, 7, 1>> dq(robot_state.dq.data()); - Eigen::Map<Eigen::Matrix<double, 7, 1>> tau_J_d( // NOLINT (readability-identifier-naming) - robot_state.tau_J_d.data()); - Eigen::Affine3d transform(Eigen::Matrix4d::Map(robot_state.O_T_EE.data())); - Eigen::Vector3d position(transform.translation()); - Eigen::Quaterniond orientation(transform.rotation()); - ee_rpy_world_mes_ = orient_utils::quaternionToRPY(orientation, ee_rpy_world_mes_prev_); - // std::cout << "Desired EE pos [m]:\t" << ee_pos_world_des_.transpose() << std::endl; - // std::cout << "Measured EE pos [m]:\t" << position.transpose() << std::endl << std::endl; - // std::cout << "Desired EE RPY [rad]:\t" << ee_rpy_world_des_.transpose() << std::endl; - // std::cout << "Measured EE RPY [rad]:\t" << ee_rpy_world_mes_.transpose() << std::endl << - // std::endl; - - // compute error to desired pose - // position error - Eigen::Matrix<double, 6, 1> error; - error.head(3) << position - ee_pos_world_des_; - - // orientation error - if (ee_quat_world_des_.coeffs().dot(orientation.coeffs()) < 0.0) - { - orientation.coeffs() << -orientation.coeffs(); - } - // "difference" quaternion - Eigen::Quaterniond error_quaternion(orientation.inverse() * ee_quat_world_des_); - 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 - // allocate variables - Eigen::VectorXd tau_task(7), tau_nullspace(7), tau_d(7), tau_fr(7); - - tau_fr.setZero(); - - // pseudoinverse for nullspace handling - // kinematic pseuoinverse - Eigen::MatrixXd jacobian_transpose_pinv; - pseudoInverse(jacobian.transpose(), jacobian_transpose_pinv); - - // Cartesian PD control with damping ratio = 1 - tau_task << jacobian.transpose() * - (-cartesian_stiffness_ * error - cartesian_damping_ * (jacobian * dq)); - // nullspace PD control with damping ratio = 1 - tau_nullspace << (Eigen::MatrixXd::Identity(7, 7) - - jacobian.transpose() * jacobian_transpose_pinv) * - (nullspace_stiffness_ * (q_d_nullspace_ - q) - - (2.0 * sqrt(nullspace_stiffness_)) * dq); - - // calculate friction torque - for (size_t i = 0; i < 7; i++) - { - tau_fr(i) = fric_phi1[i] / (1 + exp(-fric_phi2[i] * (dq(i) + fric_phi3[i]))) - - fric_phi1[i] / (1 + exp(-fric_phi2[i] * fric_phi3[i])); - } - - // Desired torque - tau_d << tau_task + tau_nullspace + coriolis + tau_fr; - - // Saturate torque rate to avoid discontinuities - tau_d << saturateTorqueRate(tau_d, tau_J_d); - // std::cout << "Desired torque:\t" << tau_d.transpose() << std::endl; - for (size_t i = 0; i < 7; ++i) - { - joint_handles_[i].setCommand(tau_d(i)); - } - - /* update previous states */ - ee_vel_world_des_prev_ = ee_vel_world_des_; - ee_acc_world_des_prev_ = ee_acc_world_des_; - ee_rpy_world_des_prev_ = ee_rpy_world_des_; - ee_rpy_world_mes_prev_ = ee_rpy_world_mes_; - - // update parameters changed online either through dynamic reconfigure or through the interactive - // target by filtering - cartesian_stiffness_ = - filter_params_ * cartesian_stiffness_target_ + (1.0 - filter_params_) * cartesian_stiffness_; - cartesian_damping_ = - filter_params_ * cartesian_damping_target_ + (1.0 - filter_params_) * cartesian_damping_; - nullspace_stiffness_ = - filter_params_ * nullspace_stiffness_target_ + (1.0 - filter_params_) * nullspace_stiffness_; - std::lock_guard<std::mutex> position_d_target_mutex_lock( - position_and_orientation_d_target_mutex_); - position_d_ = filter_params_ * position_d_target_ + (1.0 - filter_params_) * position_d_; - orientation_d_ = orientation_d_.slerp(filter_params_, orientation_d_target_); -} - -Eigen::Matrix<double, 7, 1> CartesianImpedanceExampleController::saturateTorqueRate( - const Eigen::Matrix<double, 7, 1> & tau_d_calculated, const Eigen::Matrix<double, 7, 1> & tau_J_d) -{ // NOLINT (readability-identifier-naming) - Eigen::Matrix<double, 7, 1> tau_d_saturated{}; - for (size_t i = 0; i < 7; i++) - { - double difference = tau_d_calculated[i] - tau_J_d[i]; - tau_d_saturated[i] = - tau_J_d[i] + std::max(std::min(difference, delta_tau_max_), -delta_tau_max_); - } - return tau_d_saturated; -} - -void CartesianImpedanceExampleController::complianceParamCallback( - franka_example_controllers::compliance_paramConfig & config, uint32_t /*level*/) -{ - cartesian_stiffness_target_.setIdentity(); - - // 26.4.23 @Kevin, change so can set stiffness independent per DOF - // cartesian_stiffness_target_.topLeftCorner(3, 3) - // << config.translational_stiffness * Eigen::Matrix3d::Identity(); - cartesian_stiffness_target_(0, 0) = config.translational_stiffness_x; - cartesian_stiffness_target_(1, 1) = config.translational_stiffness_y; - cartesian_stiffness_target_(2, 2) = config.translational_stiffness_z; - - cartesian_stiffness_target_.bottomRightCorner(3, 3) - << config.rotational_stiffness * Eigen::Matrix3d::Identity(); - cartesian_damping_target_.setIdentity(); - // Damping ratio = 1 - for (size_t i = 0; i < 6; i++) - { - cartesian_damping_target_(i, i) = 2.0 * sqrt(cartesian_stiffness_target_(i, i)); - } - nullspace_stiffness_target_ = config.nullspace_stiffness; -} - -void CartesianImpedanceExampleController::equilibriumPoseCallback( - const geometry_msgs::PoseStampedConstPtr & msg) -{ - std::lock_guard<std::mutex> position_d_target_mutex_lock( - position_and_orientation_d_target_mutex_); - position_d_target_ << msg->pose.position.x, msg->pose.position.y, msg->pose.position.z; - Eigen::Quaterniond last_orientation_d_target(orientation_d_target_); - orientation_d_target_.coeffs() << msg->pose.orientation.x, msg->pose.orientation.y, - msg->pose.orientation.z, msg->pose.orientation.w; - if (last_orientation_d_target.coeffs().dot(orientation_d_target_.coeffs()) < 0.0) - { - orientation_d_target_.coeffs() << -orientation_d_target_.coeffs(); - } -} - -void CartesianImpedanceExampleController::subscribe_target_twist( - const geometry_msgs::TwistConstPtr & msg) -{ - // std::cout << msg->linear.x << ", " << msg->linear.y << ", " << msg->linear.z << std::endl; - ee_vel_world_des_[0] = ee_vel_scale_[0] * msg->linear.x; - ee_vel_world_des_[1] = ee_vel_scale_[1] * msg->linear.y; - ee_vel_world_des_[2] = ee_vel_scale_[2] * msg->linear.z; - ee_vel_world_des_[3] = ee_vel_scale_[3] * msg->angular.x; - ee_vel_world_des_[4] = ee_vel_scale_[4] * msg->angular.y; - ee_vel_world_des_[5] = ee_vel_scale_[5] * msg->angular.z; -} - -void CartesianImpedanceExampleController::subscribe_joy_command( - const sensor_msgs::JoyConstPtr & msg) -{ - btn_cmd_[0] = msg->buttons[0]; - btn_cmd_[1] = msg->buttons[1]; -} - -} // namespace franka_example_controllers - -PLUGINLIB_EXPORT_CLASS(franka_example_controllers::CartesianImpedanceExampleController, - controller_interface::ControllerBase)