2024-10-04 20:14:34 +08:00
|
|
|
//
|
|
|
|
// Created by tlab-uav on 24-10-4.
|
|
|
|
//
|
|
|
|
|
2024-10-15 20:17:03 +08:00
|
|
|
#include "RlQuadrupedController.h"
|
2024-10-21 21:47:25 +08:00
|
|
|
#include <ament_index_cpp/get_package_share_directory.hpp>
|
2024-10-04 20:14:34 +08:00
|
|
|
|
2024-10-10 21:22:58 +08:00
|
|
|
namespace rl_quadruped_controller {
|
2024-10-04 20:14:34 +08:00
|
|
|
using config_type = controller_interface::interface_configuration_type;
|
|
|
|
|
|
|
|
controller_interface::InterfaceConfiguration LeggedGymController::command_interface_configuration() const {
|
|
|
|
controller_interface::InterfaceConfiguration conf = {config_type::INDIVIDUAL, {}};
|
|
|
|
|
|
|
|
conf.names.reserve(joint_names_.size() * command_interface_types_.size());
|
|
|
|
for (const auto &joint_name: joint_names_) {
|
|
|
|
for (const auto &interface_type: command_interface_types_) {
|
2024-10-08 21:36:42 +08:00
|
|
|
if (!command_prefix_.empty()) {
|
|
|
|
conf.names.push_back(command_prefix_ + "/" + joint_name + "/" += interface_type);
|
|
|
|
} else {
|
|
|
|
conf.names.push_back(joint_name + "/" += interface_type);
|
|
|
|
}
|
2024-10-04 20:14:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::InterfaceConfiguration LeggedGymController::state_interface_configuration() const {
|
|
|
|
controller_interface::InterfaceConfiguration conf = {config_type::INDIVIDUAL, {}};
|
|
|
|
|
|
|
|
conf.names.reserve(joint_names_.size() * state_interface_types_.size());
|
|
|
|
for (const auto &joint_name: joint_names_) {
|
|
|
|
for (const auto &interface_type: state_interface_types_) {
|
|
|
|
conf.names.push_back(joint_name + "/" += interface_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &interface_type: imu_interface_types_) {
|
|
|
|
conf.names.push_back(imu_name_ + "/" += interface_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &interface_type: foot_force_interface_types_) {
|
|
|
|
conf.names.push_back(foot_force_name_ + "/" += interface_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::return_type LeggedGymController::
|
|
|
|
update(const rclcpp::Time & /*time*/, const rclcpp::Duration & /*period*/) {
|
2024-10-21 21:47:25 +08:00
|
|
|
if (ctrl_comp_.enable_estimator_) {
|
|
|
|
if (ctrl_comp_.robot_model_ == nullptr) {
|
|
|
|
return controller_interface::return_type::OK;
|
|
|
|
}
|
2024-10-15 20:17:03 +08:00
|
|
|
|
2024-10-21 21:47:25 +08:00
|
|
|
ctrl_comp_.robot_model_->update();
|
|
|
|
ctrl_comp_.estimator_->update();
|
|
|
|
}
|
2024-10-15 20:17:03 +08:00
|
|
|
|
2024-10-04 20:14:34 +08:00
|
|
|
if (mode_ == FSMMode::NORMAL) {
|
|
|
|
current_state_->run();
|
|
|
|
next_state_name_ = current_state_->checkChange();
|
|
|
|
if (next_state_name_ != current_state_->state_name) {
|
|
|
|
mode_ = FSMMode::CHANGE;
|
|
|
|
next_state_ = getNextState(next_state_name_);
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Switched from %s to %s",
|
|
|
|
current_state_->state_name_string.c_str(), next_state_->state_name_string.c_str());
|
|
|
|
}
|
|
|
|
} else if (mode_ == FSMMode::CHANGE) {
|
|
|
|
current_state_->exit();
|
|
|
|
current_state_ = next_state_;
|
|
|
|
|
|
|
|
current_state_->enter();
|
|
|
|
mode_ = FSMMode::NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return controller_interface::return_type::OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn LeggedGymController::on_init() {
|
|
|
|
try {
|
|
|
|
joint_names_ = auto_declare<std::vector<std::string> >("joints", joint_names_);
|
|
|
|
feet_names_ = auto_declare<std::vector<std::string> >("feet_names", feet_names_);
|
|
|
|
command_interface_types_ =
|
|
|
|
auto_declare<std::vector<std::string> >("command_interfaces", command_interface_types_);
|
|
|
|
state_interface_types_ =
|
|
|
|
auto_declare<std::vector<std::string> >("state_interfaces", state_interface_types_);
|
|
|
|
|
2024-10-08 21:36:42 +08:00
|
|
|
command_prefix_ = auto_declare<std::string>("command_prefix", command_prefix_);
|
2024-10-15 20:17:03 +08:00
|
|
|
base_name_ = auto_declare<std::string>("base_name", base_name_);
|
2024-10-08 21:36:42 +08:00
|
|
|
|
2024-10-04 20:14:34 +08:00
|
|
|
// imu sensor
|
|
|
|
imu_name_ = auto_declare<std::string>("imu_name", imu_name_);
|
|
|
|
imu_interface_types_ = auto_declare<std::vector<std::string> >("imu_interfaces", state_interface_types_);
|
2024-10-07 11:57:32 +08:00
|
|
|
|
2024-10-15 20:17:03 +08:00
|
|
|
// foot_force_sensor
|
|
|
|
foot_force_name_ = auto_declare<std::string>("foot_force_name", foot_force_name_);
|
|
|
|
foot_force_interface_types_ =
|
2024-10-15 22:40:15 +08:00
|
|
|
auto_declare<std::vector<std::string> >("foot_force_interfaces", foot_force_interface_types_);
|
2024-10-15 20:17:03 +08:00
|
|
|
|
2024-10-07 11:57:32 +08:00
|
|
|
// rl config folder
|
2024-10-21 21:47:25 +08:00
|
|
|
robot_pkg_ = auto_declare<std::string>("robot_pkg", robot_pkg_);
|
|
|
|
model_folder_ = auto_declare<std::string>("model_folder", model_folder_);
|
2024-10-07 11:57:32 +08:00
|
|
|
|
2024-10-21 17:40:42 +08:00
|
|
|
// pose parameters
|
|
|
|
down_pos_ = auto_declare<std::vector<double> >("down_pos", down_pos_);
|
|
|
|
stand_pos_ = auto_declare<std::vector<double> >("stand_pos", stand_pos_);
|
|
|
|
stand_kp_ = auto_declare<double>("stand_kp", stand_kp_);
|
|
|
|
stand_kd_ = auto_declare<double>("stand_kd", stand_kd_);
|
|
|
|
|
2024-10-08 21:36:42 +08:00
|
|
|
get_node()->get_parameter("update_rate", ctrl_comp_.frequency_);
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Controller Update Rate: %d Hz", ctrl_comp_.frequency_);
|
2024-10-15 20:17:03 +08:00
|
|
|
|
2024-10-21 21:47:25 +08:00
|
|
|
if (foot_force_interface_types_.size() == 4) {
|
|
|
|
ctrl_comp_.enable_estimator_ = true;
|
|
|
|
ctrl_comp_.estimator_ = std::make_shared<Estimator>(ctrl_comp_);
|
|
|
|
}
|
2024-10-04 20:14:34 +08:00
|
|
|
} catch (const std::exception &e) {
|
|
|
|
fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what());
|
|
|
|
return controller_interface::CallbackReturn::ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn LeggedGymController::on_configure(
|
|
|
|
const rclcpp_lifecycle::State & /*previous_state*/) {
|
2024-10-15 20:17:03 +08:00
|
|
|
robot_description_subscription_ = get_node()->create_subscription<std_msgs::msg::String>(
|
|
|
|
"/robot_description", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local(),
|
|
|
|
[this](const std_msgs::msg::String::SharedPtr msg) {
|
2024-10-21 21:47:25 +08:00
|
|
|
if (ctrl_comp_.enable_estimator_) {
|
|
|
|
ctrl_comp_.robot_model_ = std::make_shared<QuadrupedRobot>(
|
|
|
|
ctrl_comp_, msg->data, feet_names_, base_name_);
|
|
|
|
}
|
2024-10-15 20:17:03 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
|
2024-10-04 20:14:34 +08:00
|
|
|
control_input_subscription_ = get_node()->create_subscription<control_input_msgs::msg::Inputs>(
|
|
|
|
"/control_input", 10, [this](const control_input_msgs::msg::Inputs::SharedPtr msg) {
|
|
|
|
// Handle message
|
|
|
|
ctrl_comp_.control_inputs_.command = msg->command;
|
|
|
|
ctrl_comp_.control_inputs_.lx = msg->lx;
|
|
|
|
ctrl_comp_.control_inputs_.ly = msg->ly;
|
|
|
|
ctrl_comp_.control_inputs_.rx = msg->rx;
|
|
|
|
ctrl_comp_.control_inputs_.ry = msg->ry;
|
|
|
|
});
|
|
|
|
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn LeggedGymController::on_activate(
|
|
|
|
const rclcpp_lifecycle::State & /*previous_state*/) {
|
|
|
|
// clear out vectors in case of restart
|
|
|
|
ctrl_comp_.clear();
|
|
|
|
|
|
|
|
// assign command interfaces
|
|
|
|
for (auto &interface: command_interfaces_) {
|
|
|
|
std::string interface_name = interface.get_interface_name();
|
|
|
|
if (const size_t pos = interface_name.find('/'); pos != std::string::npos) {
|
|
|
|
command_interface_map_[interface_name.substr(pos + 1)]->push_back(interface);
|
|
|
|
} else {
|
|
|
|
command_interface_map_[interface_name]->push_back(interface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// assign state interfaces
|
|
|
|
for (auto &interface: state_interfaces_) {
|
|
|
|
if (interface.get_prefix_name() == imu_name_) {
|
|
|
|
ctrl_comp_.imu_state_interface_.emplace_back(interface);
|
|
|
|
} else if (interface.get_prefix_name() == foot_force_name_) {
|
|
|
|
ctrl_comp_.foot_force_state_interface_.emplace_back(interface);
|
|
|
|
} else {
|
|
|
|
state_interface_map_[interface.get_interface_name()]->push_back(interface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create FSM List
|
|
|
|
state_list_.passive = std::make_shared<StatePassive>(ctrl_comp_);
|
2024-10-21 17:40:42 +08:00
|
|
|
state_list_.fixedDown = std::make_shared<StateFixedDown>(ctrl_comp_, down_pos_, stand_kp_, stand_kd_);
|
|
|
|
state_list_.fixedStand = std::make_shared<StateFixedStand>(ctrl_comp_, stand_pos_, stand_kp_, stand_kd_);
|
2024-10-21 21:47:25 +08:00
|
|
|
|
|
|
|
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Using robot model from %s", robot_pkg_.c_str());
|
|
|
|
const std::string package_share_directory = ament_index_cpp::get_package_share_directory(robot_pkg_);
|
|
|
|
std::string model_path = package_share_directory + "/config/" + model_folder_;
|
|
|
|
state_list_.rl = std::make_shared<StateRL>(ctrl_comp_, model_path, stand_pos_);
|
2024-10-04 20:14:34 +08:00
|
|
|
|
|
|
|
// Initialize FSM
|
|
|
|
current_state_ = state_list_.passive;
|
|
|
|
current_state_->enter();
|
|
|
|
next_state_ = current_state_;
|
|
|
|
next_state_name_ = current_state_->state_name;
|
|
|
|
mode_ = FSMMode::NORMAL;
|
|
|
|
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn LeggedGymController::on_deactivate(
|
|
|
|
const rclcpp_lifecycle::State & /*previous_state*/) {
|
|
|
|
release_interfaces();
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn
|
|
|
|
LeggedGymController::on_cleanup(const rclcpp_lifecycle::State &previous_state) {
|
|
|
|
return ControllerInterface::on_cleanup(previous_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn
|
|
|
|
LeggedGymController::on_shutdown(const rclcpp_lifecycle::State &previous_state) {
|
|
|
|
return ControllerInterface::on_shutdown(previous_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn LeggedGymController::on_error(const rclcpp_lifecycle::State &previous_state) {
|
|
|
|
return ControllerInterface::on_error(previous_state);
|
|
|
|
}
|
|
|
|
|
2024-10-07 11:57:32 +08:00
|
|
|
std::shared_ptr<FSMState> LeggedGymController::getNextState(const FSMStateName stateName) const {
|
2024-10-04 20:14:34 +08:00
|
|
|
switch (stateName) {
|
|
|
|
case FSMStateName::INVALID:
|
|
|
|
return state_list_.invalid;
|
|
|
|
case FSMStateName::PASSIVE:
|
|
|
|
return state_list_.passive;
|
|
|
|
case FSMStateName::FIXEDDOWN:
|
|
|
|
return state_list_.fixedDown;
|
|
|
|
case FSMStateName::FIXEDSTAND:
|
|
|
|
return state_list_.fixedStand;
|
2024-10-07 11:57:32 +08:00
|
|
|
case FSMStateName::RL:
|
|
|
|
return state_list_.rl;
|
2024-10-04 20:14:34 +08:00
|
|
|
default:
|
|
|
|
return state_list_.invalid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "pluginlib/class_list_macros.hpp"
|
2024-10-10 21:22:58 +08:00
|
|
|
PLUGINLIB_EXPORT_CLASS(rl_quadruped_controller::LeggedGymController, controller_interface::ControllerInterface);
|