2024-09-09 22:18:19 +08:00
|
|
|
//
|
|
|
|
// Created by biao on 24-9-9.
|
|
|
|
//
|
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
#include "hardware_unitree_mujoco/HardwareUnitree.h"
|
|
|
|
#include "crc32.h"
|
2024-09-09 22:18:19 +08:00
|
|
|
|
|
|
|
#define TOPIC_LOWCMD "rt/lowcmd"
|
|
|
|
#define TOPIC_LOWSTATE "rt/lowstate"
|
2025-01-16 16:56:04 +08:00
|
|
|
#define TOPIC_HIGHSTATE "rt/sportmodestate"
|
2024-09-09 22:18:19 +08:00
|
|
|
|
|
|
|
using namespace unitree::robot;
|
|
|
|
using hardware_interface::return_type;
|
|
|
|
|
|
|
|
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn HardwareUnitree::on_init(
|
|
|
|
const hardware_interface::HardwareInfo &info) {
|
|
|
|
if (SystemInterface::on_init(info) != CallbackReturn::SUCCESS) {
|
|
|
|
return CallbackReturn::ERROR;
|
|
|
|
}
|
|
|
|
|
2024-09-19 22:45:08 +08:00
|
|
|
joint_torque_command_.assign(12, 0);
|
2024-09-09 22:18:19 +08:00
|
|
|
joint_position_command_.assign(12, 0);
|
|
|
|
joint_velocities_command_.assign(12, 0);
|
|
|
|
joint_kp_command_.assign(12, 0);
|
|
|
|
joint_kd_command_.assign(12, 0);
|
|
|
|
|
|
|
|
joint_position_.assign(12, 0);
|
|
|
|
joint_velocities_.assign(12, 0);
|
|
|
|
joint_effort_.assign(12, 0);
|
|
|
|
|
2024-09-14 11:41:38 +08:00
|
|
|
imu_states_.assign(10, 0);
|
2024-09-24 17:13:51 +08:00
|
|
|
foot_force_.assign(4, 0);
|
2025-01-16 16:56:04 +08:00
|
|
|
high_states_.assign(6, 0);
|
2024-09-14 11:41:38 +08:00
|
|
|
|
2024-09-09 22:18:19 +08:00
|
|
|
for (const auto &joint: info_.joints) {
|
|
|
|
for (const auto &interface: joint.state_interfaces) {
|
|
|
|
joint_interfaces[interface.name].push_back(joint.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-29 10:59:00 +08:00
|
|
|
|
|
|
|
if (const auto network_interface_param = info.hardware_parameters.find("network_interface"); network_interface_param != info.hardware_parameters.end()) {
|
|
|
|
network_interface_ = network_interface_param->second;
|
|
|
|
}
|
|
|
|
if (const auto domain_param = info.hardware_parameters.find("domain"); domain_param != info.hardware_parameters.end()) {
|
|
|
|
domain_ = std::stoi(domain_param->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
RCLCPP_INFO(get_logger()," network_interface: %s, domain: %d", network_interface_.c_str(), domain_);
|
|
|
|
ChannelFactory::Instance()->Init(domain_, network_interface_);
|
2025-01-16 16:56:04 +08:00
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_publisher_ =
|
2024-09-09 22:18:19 +08:00
|
|
|
std::make_shared<ChannelPublisher<unitree_go::msg::dds_::LowCmd_> >(
|
|
|
|
TOPIC_LOWCMD);
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_publisher_->InitChannel();
|
2024-09-09 22:18:19 +08:00
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
lows_tate_subscriber_ =
|
2024-09-09 22:18:19 +08:00
|
|
|
std::make_shared<ChannelSubscriber<unitree_go::msg::dds_::LowState_> >(
|
|
|
|
TOPIC_LOWSTATE);
|
2024-09-18 22:27:16 +08:00
|
|
|
lows_tate_subscriber_->InitChannel(
|
2024-09-09 22:18:19 +08:00
|
|
|
[this](auto &&PH1) {
|
2024-09-18 22:27:16 +08:00
|
|
|
lowStateMessageHandle(std::forward<decltype(PH1)>(PH1));
|
2024-09-09 22:18:19 +08:00
|
|
|
},
|
|
|
|
1);
|
2024-09-18 22:27:16 +08:00
|
|
|
initLowCmd();
|
2024-09-09 22:18:19 +08:00
|
|
|
|
2025-01-16 16:56:04 +08:00
|
|
|
high_state_subscriber_ =
|
|
|
|
std::make_shared<ChannelSubscriber<unitree_go::msg::dds_::SportModeState_> >(
|
|
|
|
TOPIC_HIGHSTATE);
|
|
|
|
high_state_subscriber_->InitChannel(
|
|
|
|
[this](auto &&PH1) {
|
|
|
|
highStateMessageHandle(std::forward<decltype(PH1)>(PH1));
|
|
|
|
},
|
|
|
|
1);
|
|
|
|
|
2024-09-09 22:18:19 +08:00
|
|
|
|
|
|
|
return SystemInterface::on_init(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<hardware_interface::StateInterface> HardwareUnitree::export_state_interfaces() {
|
|
|
|
std::vector<hardware_interface::StateInterface> state_interfaces;
|
|
|
|
|
|
|
|
int ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["position"]) {
|
|
|
|
state_interfaces.emplace_back(joint_name, "position", &joint_position_[ind++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["velocity"]) {
|
|
|
|
state_interfaces.emplace_back(joint_name, "velocity", &joint_velocities_[ind++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["effort"]) {
|
|
|
|
state_interfaces.emplace_back(joint_name, "effort", &joint_velocities_[ind++]);
|
|
|
|
}
|
|
|
|
|
2024-09-14 11:41:38 +08:00
|
|
|
// export imu sensor state interface
|
|
|
|
for (uint i = 0; i < info_.sensors[0].state_interfaces.size(); i++) {
|
|
|
|
state_interfaces.emplace_back(
|
|
|
|
info_.sensors[0].name, info_.sensors[0].state_interfaces[i].name, &imu_states_[i]);
|
|
|
|
}
|
|
|
|
|
2024-09-24 17:13:51 +08:00
|
|
|
// export foot force sensor state interface
|
2025-01-16 16:56:04 +08:00
|
|
|
if (info_.sensors.size() > 1) {
|
|
|
|
for (uint i = 0; i < info_.sensors[1].state_interfaces.size(); i++) {
|
|
|
|
state_interfaces.emplace_back(
|
|
|
|
info_.sensors[1].name, info_.sensors[1].state_interfaces[i].name, &foot_force_[i]);
|
|
|
|
}
|
2024-09-24 17:13:51 +08:00
|
|
|
}
|
|
|
|
|
2025-01-16 16:56:04 +08:00
|
|
|
// export odometer state interface
|
|
|
|
if (info_.sensors.size() > 2) {
|
|
|
|
// export high state interface
|
|
|
|
for (uint i = 0; i < info_.sensors[2].state_interfaces.size(); i++) {
|
|
|
|
state_interfaces.emplace_back(
|
|
|
|
info_.sensors[2].name, info_.sensors[2].state_interfaces[i].name, &high_states_[i]);
|
|
|
|
}
|
|
|
|
}
|
2024-09-14 11:41:38 +08:00
|
|
|
|
2025-01-16 16:56:04 +08:00
|
|
|
|
|
|
|
return
|
|
|
|
state_interfaces;
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<hardware_interface::CommandInterface> HardwareUnitree::export_command_interfaces() {
|
|
|
|
std::vector<hardware_interface::CommandInterface> command_interfaces;
|
|
|
|
|
|
|
|
int ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["position"]) {
|
|
|
|
command_interfaces.emplace_back(joint_name, "position", &joint_position_command_[ind++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["velocity"]) {
|
|
|
|
command_interfaces.emplace_back(joint_name, "velocity", &joint_velocities_command_[ind++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ind = 0;
|
|
|
|
for (const auto &joint_name: joint_interfaces["effort"]) {
|
2024-09-20 12:48:45 +08:00
|
|
|
command_interfaces.emplace_back(joint_name, "effort", &joint_torque_command_[ind]);
|
2024-09-09 22:18:19 +08:00
|
|
|
command_interfaces.emplace_back(joint_name, "kp", &joint_kp_command_[ind]);
|
|
|
|
command_interfaces.emplace_back(joint_name, "kd", &joint_kd_command_[ind]);
|
2024-09-10 22:30:30 +08:00
|
|
|
ind++;
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
|
|
|
return command_interfaces;
|
|
|
|
}
|
|
|
|
|
2024-09-19 22:45:08 +08:00
|
|
|
return_type HardwareUnitree::read(const rclcpp::Time & /*time*/, const rclcpp::Duration & /*period*/) {
|
2024-09-14 11:41:38 +08:00
|
|
|
// joint states
|
2024-09-09 22:18:19 +08:00
|
|
|
for (int i(0); i < 12; ++i) {
|
2024-09-18 22:27:16 +08:00
|
|
|
joint_position_[i] = low_state_.motor_state()[i].q();
|
|
|
|
joint_velocities_[i] = low_state_.motor_state()[i].dq();
|
|
|
|
joint_effort_[i] = low_state_.motor_state()[i].tau_est();
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
2024-09-14 11:41:38 +08:00
|
|
|
|
|
|
|
// imu states
|
2024-09-18 22:27:16 +08:00
|
|
|
imu_states_[0] = low_state_.imu_state().quaternion()[0]; // w
|
|
|
|
imu_states_[1] = low_state_.imu_state().quaternion()[1]; // x
|
|
|
|
imu_states_[2] = low_state_.imu_state().quaternion()[2]; // y
|
|
|
|
imu_states_[3] = low_state_.imu_state().quaternion()[3]; // z
|
|
|
|
imu_states_[4] = low_state_.imu_state().gyroscope()[0];
|
|
|
|
imu_states_[5] = low_state_.imu_state().gyroscope()[1];
|
|
|
|
imu_states_[6] = low_state_.imu_state().gyroscope()[2];
|
|
|
|
imu_states_[7] = low_state_.imu_state().accelerometer()[0];
|
|
|
|
imu_states_[8] = low_state_.imu_state().accelerometer()[1];
|
|
|
|
imu_states_[9] = low_state_.imu_state().accelerometer()[2];
|
2024-09-14 11:41:38 +08:00
|
|
|
|
2024-09-24 17:13:51 +08:00
|
|
|
// contact states
|
|
|
|
foot_force_[0] = low_state_.foot_force()[0];
|
|
|
|
foot_force_[1] = low_state_.foot_force()[1];
|
|
|
|
foot_force_[2] = low_state_.foot_force()[2];
|
|
|
|
foot_force_[3] = low_state_.foot_force()[3];
|
|
|
|
|
2025-01-16 16:56:04 +08:00
|
|
|
// high states
|
|
|
|
high_states_[0] = high_state_.position()[0];
|
|
|
|
high_states_[1] = high_state_.position()[1];
|
|
|
|
high_states_[2] = high_state_.position()[2];
|
|
|
|
high_states_[3] = high_state_.velocity()[0];
|
|
|
|
high_states_[4] = high_state_.velocity()[1];
|
|
|
|
high_states_[5] = high_state_.velocity()[2];
|
|
|
|
|
|
|
|
// RCLCPP_INFO(get_logger(), "high state: %f %f %f %f %f %f", high_states_[0], high_states_[1], high_states_[2],
|
|
|
|
// high_states_[3], high_states_[4], high_states_[5]);
|
|
|
|
|
2024-09-09 22:18:19 +08:00
|
|
|
return return_type::OK;
|
|
|
|
}
|
|
|
|
|
2024-09-19 22:45:08 +08:00
|
|
|
return_type HardwareUnitree::write(const rclcpp::Time & /*time*/, const rclcpp::Duration & /*period*/) {
|
2024-09-09 22:18:19 +08:00
|
|
|
// send command
|
|
|
|
for (int i(0); i < 12; ++i) {
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_.motor_cmd()[i].mode() = 0x01;
|
|
|
|
low_cmd_.motor_cmd()[i].q() = static_cast<float>(joint_position_command_[i]);
|
|
|
|
low_cmd_.motor_cmd()[i].dq() = static_cast<float>(joint_velocities_command_[i]);
|
|
|
|
low_cmd_.motor_cmd()[i].kp() = static_cast<float>(joint_kp_command_[i]);
|
|
|
|
low_cmd_.motor_cmd()[i].kd() = static_cast<float>(joint_kd_command_[i]);
|
2024-09-19 22:45:08 +08:00
|
|
|
low_cmd_.motor_cmd()[i].tau() = static_cast<float>(joint_torque_command_[i]);
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_.crc() = crc32_core(reinterpret_cast<uint32_t *>(&low_cmd_),
|
|
|
|
(sizeof(unitree_go::msg::dds_::LowCmd_) >> 2) - 1);
|
|
|
|
low_cmd_publisher_->Write(low_cmd_);
|
2024-09-09 22:18:19 +08:00
|
|
|
return return_type::OK;
|
|
|
|
}
|
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
void HardwareUnitree::initLowCmd() {
|
|
|
|
low_cmd_.head()[0] = 0xFE;
|
|
|
|
low_cmd_.head()[1] = 0xEF;
|
|
|
|
low_cmd_.level_flag() = 0xFF;
|
|
|
|
low_cmd_.gpio() = 0;
|
2024-09-09 22:18:19 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < 20; i++) {
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_.motor_cmd()[i].mode() =
|
2024-09-09 22:18:19 +08:00
|
|
|
0x01; // motor switch to servo (PMSM) mode
|
2024-09-18 22:27:16 +08:00
|
|
|
low_cmd_.motor_cmd()[i].q() = 0;
|
|
|
|
low_cmd_.motor_cmd()[i].kp() = 0;
|
|
|
|
low_cmd_.motor_cmd()[i].dq() = 0;
|
|
|
|
low_cmd_.motor_cmd()[i].kd() = 0;
|
|
|
|
low_cmd_.motor_cmd()[i].tau() = 0;
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-18 22:27:16 +08:00
|
|
|
void HardwareUnitree::lowStateMessageHandle(const void *messages) {
|
2024-09-24 17:13:51 +08:00
|
|
|
low_state_ = *static_cast<const unitree_go::msg::dds_::LowState_ *>(messages);
|
2024-09-09 22:18:19 +08:00
|
|
|
}
|
|
|
|
|
2025-01-16 16:56:04 +08:00
|
|
|
void HardwareUnitree::highStateMessageHandle(const void *messages) {
|
|
|
|
high_state_ = *static_cast<const unitree_go::msg::dds_::SportModeState_ *>(messages);
|
|
|
|
}
|
|
|
|
|
2024-09-09 22:18:19 +08:00
|
|
|
#include "pluginlib/class_list_macros.hpp"
|
|
|
|
|
|
|
|
PLUGINLIB_EXPORT_CLASS(
|
|
|
|
HardwareUnitree, hardware_interface::SystemInterface)
|