Add joint_position_tau parameter for smoother joint control and update related configurations
This commit is contained in:
@@ -8,10 +8,13 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(controller_interface REQUIRED)
|
||||
find_package(hardware_interface REQUIRED)
|
||||
find_package(pluginlib REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rclcpp_lifecycle REQUIRED)
|
||||
find_package(realtime_tools REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
|
||||
# FRI SDK
|
||||
set(FRI_SDK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/libFRI)
|
||||
@@ -45,10 +48,11 @@ target_compile_options(fri_client_sdk PRIVATE -fpermissive -w)
|
||||
set_target_properties(fri_client_sdk PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(fri_client_sdk PUBLIC pthread)
|
||||
|
||||
# Плагин hardware interface
|
||||
# Плагины hardware interface + controller
|
||||
add_library(${PROJECT_NAME} SHARED
|
||||
src/FRIClient.cpp
|
||||
src/IIWAHardwareInterface.cpp
|
||||
src/IIWAJointPositionController.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
@@ -58,10 +62,13 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
fri_client_sdk
|
||||
controller_interface::controller_interface
|
||||
hardware_interface::hardware_interface
|
||||
pluginlib::pluginlib
|
||||
rclcpp::rclcpp
|
||||
rclcpp_lifecycle::rclcpp_lifecycle
|
||||
realtime_tools::realtime_tools
|
||||
${std_msgs_TARGETS}
|
||||
)
|
||||
|
||||
pluginlib_export_plugin_description_file(
|
||||
@@ -69,6 +76,11 @@ pluginlib_export_plugin_description_file(
|
||||
iiwa_hardware_interface_plugin.xml
|
||||
)
|
||||
|
||||
pluginlib_export_plugin_description_file(
|
||||
controller_interface
|
||||
iiwa_controller_plugin.xml
|
||||
)
|
||||
|
||||
# Установка — только библиотека и заголовки, без config/launch/urdf
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
EXPORT export_${PROJECT_NAME}
|
||||
@@ -85,6 +97,6 @@ ament_export_include_directories(include)
|
||||
ament_export_libraries(${PROJECT_NAME})
|
||||
ament_export_targets(export_${PROJECT_NAME})
|
||||
ament_export_dependencies(
|
||||
hardware_interface pluginlib rclcpp rclcpp_lifecycle)
|
||||
controller_interface hardware_interface pluginlib rclcpp rclcpp_lifecycle realtime_tools std_msgs)
|
||||
|
||||
ament_package()
|
||||
@@ -35,7 +35,10 @@ class FRIClient : public KUKA::FRI::LBRClient
|
||||
public:
|
||||
static constexpr size_t N_JOINTS = 7;
|
||||
|
||||
explicit FRIClient(CommandMode mode = CommandMode::POSITION);
|
||||
// joint_position_tau — постоянная времени экспоненциального фильтра позиций [с].
|
||||
// Аналог joint_position_tau из lbr_fri_ros2_stack (по умолчанию 0.04 с = 40 мс).
|
||||
// Сглаживает скачки команд перед отправкой роботу → убирает писк и стук суставов.
|
||||
explicit FRIClient(CommandMode mode = CommandMode::POSITION, double joint_position_tau = 0.04);
|
||||
~FRIClient() override = default;
|
||||
|
||||
// Коллбэки FRI SDK, вызываются из friThreadFunc через ClientApplication::step()
|
||||
@@ -54,11 +57,15 @@ public:
|
||||
|
||||
private:
|
||||
CommandMode cmd_mode_;
|
||||
double joint_position_tau_;
|
||||
std::atomic<KUKA::FRI::ESessionState> session_state_{KUKA::FRI::IDLE};
|
||||
|
||||
mutable std::mutex data_mutex_;
|
||||
std::array<double, N_JOINTS> target_pos_{};
|
||||
std::array<double, N_JOINTS> target_tau_{};
|
||||
// Сглаженная позиция, которую реально отправляем роботу.
|
||||
// Инициализируется IPO-позицией в waitForCommand(), чтобы не было скачка при старте.
|
||||
std::array<double, N_JOINTS> filtered_pos_{};
|
||||
IIWAStateSnapshot snapshot_{};
|
||||
|
||||
// Обновить snapshot_ без поля ipo_pos (в Monitor-режиме getIpoJointPosition() недоступна)
|
||||
|
||||
@@ -56,6 +56,7 @@ private:
|
||||
int fri_port_{30200};
|
||||
bool simulate_{false};
|
||||
std::string cmd_mode_str_{"position"};
|
||||
double joint_position_tau_{0.04}; // постоянная времени фильтра позиций [с]
|
||||
|
||||
// Объекты FRI SDK
|
||||
std::unique_ptr<FRIClient> fri_client_;
|
||||
|
||||
@@ -9,10 +9,13 @@
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
|
||||
<depend>controller_interface</depend>
|
||||
<depend>hardware_interface</depend>
|
||||
<depend>pluginlib</depend>
|
||||
<depend>rclcpp</depend>
|
||||
<depend>rclcpp_lifecycle</depend>
|
||||
<depend>realtime_tools</depend>
|
||||
<depend>std_msgs</depend>
|
||||
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
@@ -20,10 +20,12 @@ static const char * friStateName(KUKA::FRI::ESessionState s)
|
||||
}
|
||||
}
|
||||
|
||||
FRIClient::FRIClient(CommandMode mode) : cmd_mode_(mode)
|
||||
FRIClient::FRIClient(CommandMode mode, double joint_position_tau)
|
||||
: cmd_mode_(mode), joint_position_tau_(joint_position_tau)
|
||||
{
|
||||
target_pos_.fill(0.0);
|
||||
target_tau_.fill(0.0);
|
||||
filtered_pos_.fill(0.0);
|
||||
}
|
||||
|
||||
// Вызывается только в Monitor-состояниях.
|
||||
@@ -73,10 +75,12 @@ void FRIClient::waitForCommand()
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
captureCommandingData();
|
||||
|
||||
// Инициализируем цель IPO-позицией, иначе до первого write() будем посылать нули.
|
||||
// Инициализируем цель и фильтр IPO-позицией.
|
||||
// Фильтр стартует с IPO — это гарантирует нулевой скачок при переходе в COMMANDING_ACTIVE.
|
||||
std::memcpy(target_pos_.data(), snapshot_.ipo_pos.data(), N_JOINTS * sizeof(double));
|
||||
std::memcpy(filtered_pos_.data(), snapshot_.ipo_pos.data(), N_JOINTS * sizeof(double));
|
||||
|
||||
robotCommand().setJointPosition(target_pos_.data());
|
||||
robotCommand().setJointPosition(filtered_pos_.data());
|
||||
|
||||
if (cmd_mode_ == CommandMode::TORQUE) {
|
||||
// Пока контроллер не синхронизирован, момент держим на нуле
|
||||
@@ -91,7 +95,16 @@ void FRIClient::command()
|
||||
std::lock_guard<std::mutex> lock(data_mutex_);
|
||||
captureCommandingData();
|
||||
|
||||
robotCommand().setJointPosition(target_pos_.data());
|
||||
// Экспоненциальный фильтр первого порядка: alpha = dt / (tau + dt).
|
||||
// Сглаживает скачки команд от контроллера — устраняет писк и стук суставов.
|
||||
// При tau=0.04 с и dt=0.005 с: alpha≈0.11 (11% новой команды за цикл).
|
||||
const double dt = snapshot_.sample_time;
|
||||
const double alpha = dt / (joint_position_tau_ + dt);
|
||||
for (size_t i = 0; i < N_JOINTS; ++i) {
|
||||
filtered_pos_[i] = alpha * target_pos_[i] + (1.0 - alpha) * filtered_pos_[i];
|
||||
}
|
||||
|
||||
robotCommand().setJointPosition(filtered_pos_.data());
|
||||
|
||||
if (cmd_mode_ == CommandMode::TORQUE) {
|
||||
// В режиме TORQUE позиция работает как feedforward удержания, момент добавляется поверх.
|
||||
|
||||
@@ -41,13 +41,15 @@ CallbackReturn IIWAHardwareInterface::on_init(
|
||||
fri_port_ = std::stoi(getParam(info, "fri_port", "30200"));
|
||||
simulate_ = (getParam(info, "simulate", "false") == "true");
|
||||
cmd_mode_str_ = getParam(info, "command_mode", "position");
|
||||
joint_position_tau_ = std::stod(getParam(info, "joint_position_tau", "0.04"));
|
||||
|
||||
RCLCPP_INFO(
|
||||
rclcpp::get_logger("IIWAHardwareInterface"),
|
||||
"on_init: ip=%s port=%d simulate=%s mode=%s",
|
||||
"on_init: ip=%s port=%d simulate=%s mode=%s tau=%.3f",
|
||||
robot_ip_.c_str(), fri_port_,
|
||||
simulate_ ? "true" : "false",
|
||||
cmd_mode_str_.c_str());
|
||||
cmd_mode_str_.c_str(),
|
||||
joint_position_tau_);
|
||||
|
||||
if (info.joints.size() != N_JOINTS) {
|
||||
RCLCPP_FATAL(
|
||||
@@ -114,7 +116,7 @@ CallbackReturn IIWAHardwareInterface::on_activate(const rclcpp_lifecycle::State
|
||||
return CallbackReturn::SUCCESS;
|
||||
}
|
||||
|
||||
fri_client_ = std::make_unique<FRIClient>(parseCommandMode(cmd_mode_str_));
|
||||
fri_client_ = std::make_unique<FRIClient>(parseCommandMode(cmd_mode_str_), joint_position_tau_);
|
||||
// 100 мс таймаут: если закрытие сокета не разблокирует recvfrom() мгновенно,
|
||||
// поток всё равно выйдет через одну итерацию.
|
||||
connection_ = std::make_unique<KUKA::FRI::UdpConnection>(100);
|
||||
|
||||
Reference in New Issue
Block a user