2024-09-24 19:48:14 +08:00
|
|
|
//
|
|
|
|
// Created by tlab-uav on 24-9-24.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "Ocs2QuadrupedController.h"
|
2025-02-23 22:07:46 +08:00
|
|
|
#include <ament_index_cpp/get_package_share_directory.hpp>
|
2024-09-24 21:50:46 +08:00
|
|
|
|
|
|
|
#include <ocs2_core/misc/LoadData.h>
|
|
|
|
#include <ocs2_core/thread_support/ExecuteAndSleep.h>
|
|
|
|
#include <ocs2_core/thread_support/SetThreadPriority.h>
|
|
|
|
#include <ocs2_legged_robot_ros/gait/GaitReceiver.h>
|
|
|
|
#include <ocs2_quadruped_controller/estimator/LinearKalmanFilter.h>
|
|
|
|
#include <ocs2_quadruped_controller/wbc/WeightedWbc.h>
|
|
|
|
#include <ocs2_ros_interfaces/synchronized_module/RosReferenceManager.h>
|
2024-09-27 17:40:22 +08:00
|
|
|
#include <ocs2_ros_interfaces/common/RosMsgConversions.h>
|
2024-09-24 21:50:46 +08:00
|
|
|
#include <ocs2_sqp/SqpMpc.h>
|
2024-09-25 21:01:50 +08:00
|
|
|
#include <angles/angles.h>
|
2024-09-26 17:28:18 +08:00
|
|
|
#include <ocs2_quadruped_controller/control/GaitManager.h>
|
2025-01-16 16:56:04 +08:00
|
|
|
#include <ocs2_quadruped_controller/estimator/GroundTruth.h>
|
2025-02-23 22:07:46 +08:00
|
|
|
#include <ocs2_quadruped_controller/estimator/FromOdomTopic.h>
|
2024-09-24 21:50:46 +08:00
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
namespace ocs2::legged_robot
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
using config_type = controller_interface::interface_configuration_type;
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
controller_interface::InterfaceConfiguration Ocs2QuadrupedController::command_interface_configuration() const
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
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_) {
|
2025-02-23 22:07:46 +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-09-25 21:01:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
controller_interface::InterfaceConfiguration Ocs2QuadrupedController::state_interface_configuration() const
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
controller_interface::InterfaceConfiguration conf = {config_type::INDIVIDUAL, {}};
|
|
|
|
|
|
|
|
conf.names.reserve(joint_names_.size() * state_interface_types_.size());
|
2025-02-23 22:07:46 +08:00
|
|
|
for (const auto& joint_name : joint_names_)
|
|
|
|
{
|
|
|
|
for (const auto& interface_type : state_interface_types_)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
conf.names.push_back(joint_name + "/" += interface_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
for (const auto& interface_type : imu_interface_types_)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
conf.names.push_back(imu_name_ + "/" += interface_type);
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
if (estimator_type_ == "ground_truth")
|
|
|
|
{
|
|
|
|
for (const auto& interface_type : odom_interface_types_)
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
conf.names.push_back(odom_name_ + "/" += interface_type);
|
|
|
|
}
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else if (estimator_type_ == "linear_kalman")
|
|
|
|
{
|
|
|
|
for (const auto& interface_type : foot_force_interface_types_)
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
conf.names.push_back(foot_force_name_ + "/" += interface_type);
|
|
|
|
}
|
2024-09-25 21:01:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return conf;
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
controller_interface::return_type Ocs2QuadrupedController::update(const rclcpp::Time& time,
|
|
|
|
const rclcpp::Duration& period)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
// State Estimate
|
2025-02-23 22:07:46 +08:00
|
|
|
updateStateEstimation(period);
|
2024-09-25 21:01:50 +08:00
|
|
|
|
2024-09-30 11:59:35 +08:00
|
|
|
// Compute target trajectory
|
|
|
|
ctrl_comp_.target_manager_->update();
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
// Update the current state of the system
|
2024-09-30 11:59:35 +08:00
|
|
|
mpc_mrt_interface_->setCurrentObservation(ctrl_comp_.observation_);
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
// Load the latest MPC policy
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_mrt_interface_->updatePolicy();
|
2025-02-23 22:07:46 +08:00
|
|
|
mpc_need_updated_ = true;
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
// Evaluate the current policy
|
2024-09-27 17:40:22 +08:00
|
|
|
vector_t optimized_state, optimized_input;
|
|
|
|
size_t planned_mode = 0; // The mode that is active at the time the policy is evaluated at.
|
2024-09-30 11:59:35 +08:00
|
|
|
mpc_mrt_interface_->evaluatePolicy(ctrl_comp_.observation_.time, ctrl_comp_.observation_.state, optimized_state,
|
2024-09-27 17:40:22 +08:00
|
|
|
optimized_input, planned_mode);
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
// Whole body control
|
2024-09-30 11:59:35 +08:00
|
|
|
ctrl_comp_.observation_.input = optimized_input;
|
2024-09-25 21:01:50 +08:00
|
|
|
|
2024-09-26 22:18:11 +08:00
|
|
|
wbc_timer_.startTimer();
|
2024-09-30 11:59:35 +08:00
|
|
|
vector_t x = wbc_->update(optimized_state, optimized_input, measured_rbd_state_, planned_mode,
|
|
|
|
period.seconds());
|
2024-09-26 22:18:11 +08:00
|
|
|
wbc_timer_.endTimer();
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
vector_t torque = x.tail(12);
|
|
|
|
|
2024-09-30 11:59:35 +08:00
|
|
|
vector_t pos_des = centroidal_model::getJointAngles(optimized_state,
|
|
|
|
legged_interface_->getCentroidalModelInfo());
|
2024-09-27 17:40:22 +08:00
|
|
|
vector_t vel_des = centroidal_model::getJointVelocities(optimized_input,
|
2024-09-30 11:59:35 +08:00
|
|
|
legged_interface_->getCentroidalModelInfo());
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
// Safety check, if failed, stop the controller
|
2025-02-23 22:07:46 +08:00
|
|
|
if (!safety_checker_->check(ctrl_comp_.observation_, optimized_state, optimized_input))
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
RCLCPP_ERROR(get_node()->get_logger(), "[Legged Controller] Safety check failed, stopping the controller.");
|
2025-02-23 22:07:46 +08:00
|
|
|
for (int i = 0; i < joint_names_.size(); i++)
|
|
|
|
{
|
2024-09-29 17:09:06 +08:00
|
|
|
ctrl_comp_.joint_torque_command_interface_[i].get().set_value(0);
|
|
|
|
ctrl_comp_.joint_position_command_interface_[i].get().set_value(0);
|
|
|
|
ctrl_comp_.joint_velocity_command_interface_[i].get().set_value(0);
|
|
|
|
ctrl_comp_.joint_kp_command_interface_[i].get().set_value(0.0);
|
|
|
|
ctrl_comp_.joint_kd_command_interface_[i].get().set_value(0.35);
|
|
|
|
}
|
2024-09-28 23:05:13 +08:00
|
|
|
return controller_interface::return_type::ERROR;
|
2024-09-25 21:01:50 +08:00
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
for (int i = 0; i < joint_names_.size(); i++)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
ctrl_comp_.joint_torque_command_interface_[i].get().set_value(torque(i));
|
2024-09-27 17:40:22 +08:00
|
|
|
ctrl_comp_.joint_position_command_interface_[i].get().set_value(pos_des(i));
|
|
|
|
ctrl_comp_.joint_velocity_command_interface_[i].get().set_value(vel_des(i));
|
2024-09-30 17:48:59 +08:00
|
|
|
ctrl_comp_.joint_kp_command_interface_[i].get().set_value(default_kp_);
|
|
|
|
ctrl_comp_.joint_kd_command_interface_[i].get().set_value(default_kd_);
|
2024-09-25 21:01:50 +08:00
|
|
|
}
|
|
|
|
|
2024-09-30 20:02:56 +08:00
|
|
|
// Visualization
|
|
|
|
ctrl_comp_.visualizer_->update(ctrl_comp_.observation_, mpc_mrt_interface_->getPolicy(),
|
|
|
|
mpc_mrt_interface_->getCommand());
|
|
|
|
|
2024-09-30 11:59:35 +08:00
|
|
|
observation_publisher_->publish(ros_msg_conversions::createObservationMsg(ctrl_comp_.observation_));
|
2024-09-27 17:40:22 +08:00
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
return controller_interface::return_type::OK;
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_init()
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
// Initialize OCS2
|
2025-02-23 22:07:46 +08:00
|
|
|
robot_pkg_ = auto_declare<std::string>("robot_pkg", robot_pkg_);
|
|
|
|
const std::string package_share_directory = ament_index_cpp::get_package_share_directory(robot_pkg_);
|
|
|
|
|
|
|
|
urdf_file_ = package_share_directory + "/urdf/robot.urdf";
|
|
|
|
task_file_ = package_share_directory + "/config/ocs2/task.info";
|
|
|
|
reference_file_ = package_share_directory + "/config/ocs2/reference.info";
|
|
|
|
gait_file_ = package_share_directory + "/config/ocs2/gait.info";
|
2024-09-25 21:01:50 +08:00
|
|
|
|
2024-10-16 22:59:11 +08:00
|
|
|
get_node()->get_parameter("update_rate", ctrl_comp_.frequency_);
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Controller Manager Update Rate: %d Hz", ctrl_comp_.frequency_);
|
|
|
|
|
2024-09-29 17:09:06 +08:00
|
|
|
// Load verbose parameter from the task file
|
2024-09-24 21:50:46 +08:00
|
|
|
verbose_ = false;
|
|
|
|
loadData::loadCppDataType(task_file_, "legged_robot_interface.verbose", verbose_);
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
// Hardware Parameters
|
2025-02-23 22:07:46 +08:00
|
|
|
command_prefix_ = auto_declare<std::string>("command_prefix", command_prefix_);
|
|
|
|
joint_names_ = auto_declare<std::vector<std::string>>("joints", joint_names_);
|
|
|
|
feet_names_ = auto_declare<std::vector<std::string>>("feet", feet_names_);
|
2024-09-25 21:01:50 +08:00
|
|
|
command_interface_types_ =
|
2025-02-23 22:07:46 +08:00
|
|
|
auto_declare<std::vector<std::string>>("command_interfaces", command_interface_types_);
|
2024-09-25 21:01:50 +08:00
|
|
|
state_interface_types_ =
|
2025-02-23 22:07:46 +08:00
|
|
|
auto_declare<std::vector<std::string>>("state_interfaces", state_interface_types_);
|
2025-01-16 16:56:04 +08:00
|
|
|
|
|
|
|
// IMU Sensor
|
2024-09-25 21:01:50 +08:00
|
|
|
imu_name_ = auto_declare<std::string>("imu_name", imu_name_);
|
2025-02-23 22:07:46 +08:00
|
|
|
imu_interface_types_ = auto_declare<std::vector<std::string>>("imu_interfaces", state_interface_types_);
|
2025-01-16 16:56:04 +08:00
|
|
|
|
|
|
|
// Odometer Sensor (Ground Truth)
|
2025-02-23 22:07:46 +08:00
|
|
|
estimator_type_ = auto_declare<std::string>("estimator_type", estimator_type_);
|
|
|
|
if (estimator_type_ == "ground_truth")
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
odom_name_ = auto_declare<std::string>("odom_name", odom_name_);
|
2025-02-23 22:07:46 +08:00
|
|
|
odom_interface_types_ = auto_declare<std::vector<std::string>>("odom_interfaces", state_interface_types_);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
// Foot Force Sensor
|
|
|
|
foot_force_name_ = auto_declare<std::string>("foot_force_name", foot_force_name_);
|
|
|
|
foot_force_interface_types_ =
|
2025-02-23 22:07:46 +08:00
|
|
|
auto_declare<std::vector<std::string>>("foot_force_interfaces", state_interface_types_);
|
2025-01-16 16:56:04 +08:00
|
|
|
}
|
2024-09-25 21:01:50 +08:00
|
|
|
|
2024-09-30 17:48:59 +08:00
|
|
|
// PD gains
|
|
|
|
default_kp_ = auto_declare<double>("default_kp", default_kp_);
|
|
|
|
default_kd_ = auto_declare<double>("default_kd", default_kd_);
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
setupLeggedInterface();
|
2024-09-24 21:50:46 +08:00
|
|
|
setupMpc();
|
|
|
|
setupMrt();
|
|
|
|
|
|
|
|
// Visualization
|
2024-09-29 17:09:06 +08:00
|
|
|
CentroidalModelPinocchioMapping pinocchio_mapping(legged_interface_->getCentroidalModelInfo());
|
2024-09-24 21:50:46 +08:00
|
|
|
eeKinematicsPtr_ = std::make_shared<PinocchioEndEffectorKinematics>(
|
2024-09-29 17:09:06 +08:00
|
|
|
legged_interface_->getPinocchioInterface(), pinocchio_mapping,
|
2024-09-24 21:50:46 +08:00
|
|
|
legged_interface_->modelSettings().contactNames3DoF);
|
2024-09-30 20:02:56 +08:00
|
|
|
|
|
|
|
ctrl_comp_.visualizer_ = std::make_shared<LeggedRobotVisualizer>(
|
|
|
|
legged_interface_->getPinocchioInterface(), legged_interface_->getCentroidalModelInfo(), *eeKinematicsPtr_,
|
|
|
|
get_node());
|
|
|
|
|
2024-09-24 21:50:46 +08:00
|
|
|
// selfCollisionVisualization_.reset(new LeggedSelfCollisionVisualization(leggedInterface_->getPinocchioInterface(),
|
|
|
|
// leggedInterface_->getGeometryInterface(), pinocchioMapping, nh));
|
|
|
|
|
|
|
|
// State estimation
|
|
|
|
setupStateEstimate();
|
|
|
|
|
|
|
|
// Whole body control
|
|
|
|
wbc_ = std::make_shared<WeightedWbc>(legged_interface_->getPinocchioInterface(),
|
|
|
|
legged_interface_->getCentroidalModelInfo(),
|
|
|
|
*eeKinematicsPtr_);
|
|
|
|
wbc_->loadTasksSetting(task_file_, verbose_);
|
|
|
|
|
|
|
|
// Safety Checker
|
2024-09-26 22:18:11 +08:00
|
|
|
safety_checker_ = std::make_shared<SafetyChecker>(legged_interface_->getCentroidalModelInfo());
|
2024-09-24 21:50:46 +08:00
|
|
|
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_configure(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
control_input_subscription_ = get_node()->create_subscription<control_input_msgs::msg::Inputs>(
|
2025-02-23 22:07:46 +08:00
|
|
|
"/control_input", 10, [this](const control_input_msgs::msg::Inputs::SharedPtr msg)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
// 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;
|
|
|
|
});
|
|
|
|
|
2024-09-27 17:40:22 +08:00
|
|
|
observation_publisher_ = get_node()->create_publisher<ocs2_msgs::msg::MpcObservation>(
|
|
|
|
"legged_robot_mpc_observation", 10);
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_activate(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
// clear out vectors in case of restart
|
|
|
|
ctrl_comp_.clear();
|
|
|
|
|
|
|
|
// assign command interfaces
|
2025-02-23 22:07:46 +08:00
|
|
|
for (auto& interface : command_interfaces_)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
std::string interface_name = interface.get_interface_name();
|
2025-02-23 22:07:46 +08:00
|
|
|
if (const size_t pos = interface_name.find('/'); pos != std::string::npos)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
command_interface_map_[interface_name.substr(pos + 1)]->push_back(interface);
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
command_interface_map_[interface_name]->push_back(interface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// assign state interfaces
|
2025-02-23 22:07:46 +08:00
|
|
|
for (auto& interface : state_interfaces_)
|
|
|
|
{
|
|
|
|
if (interface.get_prefix_name() == imu_name_)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
ctrl_comp_.imu_state_interface_.emplace_back(interface);
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else if (interface.get_prefix_name() == foot_force_name_)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
ctrl_comp_.foot_force_state_interface_.emplace_back(interface);
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else if (interface.get_prefix_name() == odom_name_)
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
ctrl_comp_.odom_state_interface_.emplace_back(interface);
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
state_interface_map_[interface.get_interface_name()]->push_back(interface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
if (mpc_running_ == false)
|
|
|
|
{
|
2024-09-26 17:28:18 +08:00
|
|
|
// Initial state
|
2024-10-02 13:45:21 +08:00
|
|
|
ctrl_comp_.observation_.state.setZero(
|
|
|
|
static_cast<long>(legged_interface_->getCentroidalModelInfo().stateDim));
|
2025-02-23 22:07:46 +08:00
|
|
|
updateStateEstimation(rclcpp::Duration(0, 1 / ctrl_comp_.frequency_ * 1000000000));
|
2024-10-02 13:45:21 +08:00
|
|
|
ctrl_comp_.observation_.input.setZero(
|
|
|
|
static_cast<long>(legged_interface_->getCentroidalModelInfo().inputDim));
|
2024-09-30 11:59:35 +08:00
|
|
|
ctrl_comp_.observation_.mode = STANCE;
|
2024-09-26 17:28:18 +08:00
|
|
|
|
2024-10-02 13:45:21 +08:00
|
|
|
const TargetTrajectories target_trajectories({ctrl_comp_.observation_.time},
|
|
|
|
{ctrl_comp_.observation_.state},
|
2024-09-30 11:59:35 +08:00
|
|
|
{ctrl_comp_.observation_.input});
|
2024-09-26 17:28:18 +08:00
|
|
|
|
|
|
|
// Set the first observation and command and wait for optimization to finish
|
2024-09-30 11:59:35 +08:00
|
|
|
mpc_mrt_interface_->setCurrentObservation(ctrl_comp_.observation_);
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_mrt_interface_->getReferenceManager().setTargetTrajectories(target_trajectories);
|
2024-09-26 17:28:18 +08:00
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Waiting for the initial policy ...");
|
2025-02-23 22:07:46 +08:00
|
|
|
while (!mpc_mrt_interface_->initialPolicyReceived())
|
|
|
|
{
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_mrt_interface_->advanceMpc();
|
2024-09-26 17:28:18 +08:00
|
|
|
rclcpp::WallRate(legged_interface_->mpcSettings().mrtDesiredFrequency_).sleep();
|
|
|
|
}
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Initial policy has been received.");
|
|
|
|
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_running_ = true;
|
2024-09-26 17:28:18 +08:00
|
|
|
}
|
|
|
|
|
2024-09-25 21:01:50 +08:00
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_deactivate(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
release_interfaces();
|
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_cleanup(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_shutdown(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
controller_interface::CallbackReturn Ocs2QuadrupedController::on_error(
|
2025-02-23 22:07:46 +08:00
|
|
|
const rclcpp_lifecycle::State& /*previous_state*/)
|
|
|
|
{
|
2024-09-25 21:01:50 +08:00
|
|
|
return CallbackReturn::SUCCESS;
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
void Ocs2QuadrupedController::setupLeggedInterface()
|
|
|
|
{
|
2024-09-24 21:50:46 +08:00
|
|
|
legged_interface_ = std::make_shared<LeggedInterface>(task_file_, urdf_file_, reference_file_);
|
2024-10-02 13:45:21 +08:00
|
|
|
legged_interface_->setupJointNames(joint_names_, feet_names_);
|
2024-09-24 21:50:46 +08:00
|
|
|
legged_interface_->setupOptimalControlProblem(task_file_, urdf_file_, reference_file_, verbose_);
|
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
void Ocs2QuadrupedController::setupMpc()
|
|
|
|
{
|
2024-09-24 21:50:46 +08:00
|
|
|
mpc_ = std::make_shared<SqpMpc>(legged_interface_->mpcSettings(), legged_interface_->sqpSettings(),
|
|
|
|
legged_interface_->getOptimalControlProblem(),
|
|
|
|
legged_interface_->getInitializer());
|
2024-09-26 22:18:11 +08:00
|
|
|
rbd_conversions_ = std::make_shared<CentroidalModelRbdConversions>(legged_interface_->getPinocchioInterface(),
|
2024-09-27 17:40:22 +08:00
|
|
|
legged_interface_->getCentroidalModelInfo());
|
2024-09-24 21:50:46 +08:00
|
|
|
|
2024-09-30 11:59:35 +08:00
|
|
|
// Initialize the reference manager
|
2024-09-26 17:28:18 +08:00
|
|
|
const auto gait_manager_ptr = std::make_shared<GaitManager>(
|
|
|
|
ctrl_comp_, legged_interface_->getSwitchedModelReferenceManagerPtr()->
|
2025-02-23 22:07:46 +08:00
|
|
|
getGaitSchedule());
|
2024-09-26 17:28:18 +08:00
|
|
|
gait_manager_ptr->init(gait_file_);
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_->getSolverPtr()->addSynchronizedModule(gait_manager_ptr);
|
2024-09-30 11:59:35 +08:00
|
|
|
mpc_->getSolverPtr()->setReferenceManager(legged_interface_->getReferenceManagerPtr());
|
|
|
|
|
|
|
|
ctrl_comp_.target_manager_ = std::make_shared<TargetManager>(ctrl_comp_,
|
|
|
|
legged_interface_->getReferenceManagerPtr(),
|
|
|
|
task_file_, reference_file_);
|
2024-09-24 21:50:46 +08:00
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
void Ocs2QuadrupedController::setupMrt()
|
|
|
|
{
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_mrt_interface_ = std::make_shared<MPC_MRT_Interface>(*mpc_);
|
|
|
|
mpc_mrt_interface_->initRollout(&legged_interface_->getRollout());
|
|
|
|
mpc_timer_.reset();
|
2024-09-24 21:50:46 +08:00
|
|
|
|
2024-09-26 22:18:11 +08:00
|
|
|
controller_running_ = true;
|
2025-02-23 22:07:46 +08:00
|
|
|
mpc_thread_ = std::thread([&]
|
|
|
|
{
|
|
|
|
while (controller_running_)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2024-09-24 21:50:46 +08:00
|
|
|
executeAndSleep(
|
2025-02-23 22:07:46 +08:00
|
|
|
[&]
|
|
|
|
{
|
|
|
|
if (mpc_running_ && mpc_need_updated_)
|
|
|
|
{
|
|
|
|
mpc_need_updated_ = false;
|
2024-09-26 22:18:11 +08:00
|
|
|
mpc_timer_.startTimer();
|
|
|
|
mpc_mrt_interface_->advanceMpc();
|
|
|
|
mpc_timer_.endTimer();
|
2024-09-24 21:50:46 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
legged_interface_->mpcSettings().mpcDesiredFrequency_);
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
2024-09-26 22:18:11 +08:00
|
|
|
controller_running_ = false;
|
2024-09-24 21:50:46 +08:00
|
|
|
RCLCPP_WARN(get_node()->get_logger(), "[Ocs2 MPC thread] Error : %s", e.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2024-09-26 22:18:11 +08:00
|
|
|
setThreadPriority(legged_interface_->sqpSettings().threadPriority, mpc_thread_);
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "MRT initialized. MPC thread started.");
|
2024-09-24 21:50:46 +08:00
|
|
|
}
|
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
void Ocs2QuadrupedController::setupStateEstimate()
|
|
|
|
{
|
|
|
|
if (estimator_type_ == "ground_truth")
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
ctrl_comp_.estimator_ = std::make_shared<GroundTruth>(legged_interface_->getCentroidalModelInfo(),
|
|
|
|
ctrl_comp_,
|
|
|
|
get_node());
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Using Ground Truth Estimator");
|
2025-02-23 22:07:46 +08:00
|
|
|
}
|
|
|
|
else if (estimator_type_ == "linear_kalman")
|
|
|
|
{
|
2025-01-16 16:56:04 +08:00
|
|
|
ctrl_comp_.estimator_ = std::make_shared<KalmanFilterEstimate>(legged_interface_->getPinocchioInterface(),
|
|
|
|
legged_interface_->getCentroidalModelInfo(),
|
|
|
|
*eeKinematicsPtr_, ctrl_comp_,
|
|
|
|
get_node());
|
2025-02-23 22:07:46 +08:00
|
|
|
dynamic_cast<KalmanFilterEstimate&>(*ctrl_comp_.estimator_).loadSettings(task_file_, verbose_);
|
2025-01-16 16:56:04 +08:00
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Using Kalman Filter Estimator");
|
|
|
|
}
|
2025-02-23 22:07:46 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ctrl_comp_.estimator_ = std::make_shared<FromOdomTopic>(legged_interface_->getCentroidalModelInfo(),ctrl_comp_,get_node());
|
|
|
|
RCLCPP_INFO(get_node()->get_logger(), "Using Odom Topic Based Estimator");
|
|
|
|
}
|
2024-09-30 11:59:35 +08:00
|
|
|
ctrl_comp_.observation_.time = 0;
|
2024-09-24 21:50:46 +08:00
|
|
|
}
|
2024-09-26 17:28:18 +08:00
|
|
|
|
2025-02-23 22:07:46 +08:00
|
|
|
void Ocs2QuadrupedController::updateStateEstimation(const rclcpp::Duration& period)
|
|
|
|
{
|
|
|
|
measured_rbd_state_ = ctrl_comp_.estimator_->update(get_node()->now(), period);
|
2024-09-30 11:59:35 +08:00
|
|
|
ctrl_comp_.observation_.time += period.seconds();
|
|
|
|
const scalar_t yaw_last = ctrl_comp_.observation_.state(9);
|
|
|
|
ctrl_comp_.observation_.state = rbd_conversions_->computeCentroidalStateFromRbdModel(measured_rbd_state_);
|
|
|
|
ctrl_comp_.observation_.state(9) = yaw_last + angles::shortest_angular_distance(
|
2025-02-23 22:07:46 +08:00
|
|
|
yaw_last, ctrl_comp_.observation_.state(9));
|
2025-01-16 16:56:04 +08:00
|
|
|
// ctrl_comp_.observation_.mode = ctrl_comp_.estimator_->getMode();
|
2024-09-26 17:28:18 +08:00
|
|
|
}
|
2024-09-24 21:50:46 +08:00
|
|
|
}
|
2024-09-25 21:01:50 +08:00
|
|
|
|
|
|
|
#include "pluginlib/class_list_macros.hpp"
|
2024-09-26 17:28:18 +08:00
|
|
|
PLUGINLIB_EXPORT_CLASS(ocs2::legged_robot::Ocs2QuadrupedController, controller_interface::ControllerInterface);
|