// // Created by tlab-uav on 24-10-4. // #include "RlQuadrupedController.h" #include namespace rl_quadruped_controller { 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_) { if (!command_prefix_.empty()) { conf.names.push_back(command_prefix_ + "/" + joint_name + "/" += interface_type); } else { conf.names.push_back(joint_name + "/" += interface_type); } } } 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) { if (ctrl_component_.enable_estimator_) { if (ctrl_component_.robot_model_ == nullptr) { return controller_interface::return_type::OK; } ctrl_component_.robot_model_->update(); ctrl_component_.estimator_->update(); } if (mode_ == FSMMode::NORMAL) { current_state_->run(time, period); 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 >("joints", joint_names_); feet_names_ = auto_declare >("feet_names", feet_names_); command_interface_types_ = auto_declare >("command_interfaces", command_interface_types_); state_interface_types_ = auto_declare >("state_interfaces", state_interface_types_); command_prefix_ = auto_declare("command_prefix", command_prefix_); base_name_ = auto_declare("base_name", base_name_); // imu sensor imu_name_ = auto_declare("imu_name", imu_name_); imu_interface_types_ = auto_declare >("imu_interfaces", state_interface_types_); // foot_force_sensor foot_force_name_ = auto_declare("foot_force_name", foot_force_name_); foot_force_interface_types_ = auto_declare >("foot_force_interfaces", foot_force_interface_types_); // rl config folder robot_pkg_ = auto_declare("robot_pkg", robot_pkg_); model_folder_ = auto_declare("model_folder", model_folder_); // pose parameters down_pos_ = auto_declare >("down_pos", down_pos_); stand_pos_ = auto_declare >("stand_pos", stand_pos_); stand_kp_ = auto_declare("stand_kp", stand_kp_); stand_kd_ = auto_declare("stand_kd", stand_kd_); get_node()->get_parameter("update_rate", ctrl_interfaces_.frequency_); RCLCPP_INFO(get_node()->get_logger(), "Controller Update Rate: %d Hz", ctrl_interfaces_.frequency_); if (foot_force_interface_types_.size() == 4) { ctrl_component_.enable_estimator_ = true; ctrl_component_.estimator_ = std::make_shared(ctrl_interfaces_, ctrl_component_); } } 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*/) { robot_description_subscription_ = get_node()->create_subscription( "/robot_description", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local(), [this](const std_msgs::msg::String::SharedPtr msg) { if (ctrl_component_.enable_estimator_) { ctrl_component_.robot_model_ = std::make_shared( ctrl_interfaces_, msg->data, feet_names_, base_name_); } }); control_input_subscription_ = get_node()->create_subscription( "/control_input", 10, [this](const control_input_msgs::msg::Inputs::SharedPtr msg) { // Handle message ctrl_interfaces_.control_inputs_.command = msg->command; ctrl_interfaces_.control_inputs_.lx = msg->lx; ctrl_interfaces_.control_inputs_.ly = msg->ly; ctrl_interfaces_.control_inputs_.rx = msg->rx; ctrl_interfaces_.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_interfaces_.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_interfaces_.imu_state_interface_.emplace_back(interface); } else if (interface.get_prefix_name() == foot_force_name_) { ctrl_interfaces_.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(ctrl_interfaces_); state_list_.fixedDown = std::make_shared(ctrl_interfaces_, down_pos_, stand_kp_, stand_kd_); state_list_.fixedStand = std::make_shared(ctrl_interfaces_, stand_pos_, stand_kp_, stand_kd_); 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(ctrl_interfaces_, ctrl_component_, model_path, stand_pos_); // 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); } std::shared_ptr LeggedGymController::getNextState(const FSMStateName stateName) const { 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; case FSMStateName::RL: return state_list_.rl; default: return state_list_.invalid; } } } #include "pluginlib/class_list_macros.hpp" PLUGINLIB_EXPORT_CLASS(rl_quadruped_controller::LeggedGymController, controller_interface::ControllerInterface);