2024-02-09 01:47:33 +08:00
|
|
|
#include "unitree_go/msg/low_state.hpp"
|
|
|
|
#include "unitree_go/msg/imu_state.hpp"
|
|
|
|
#include "unitree_go/msg/motor_state.hpp"
|
2024-05-05 02:03:03 +08:00
|
|
|
#include "go2py_common/msg/go2py_status.hpp"
|
|
|
|
#include "go2py_common/msg/go2py_low_cmd.hpp"
|
2024-02-09 01:47:33 +08:00
|
|
|
|
|
|
|
#include "unitree_go/msg/low_cmd.hpp"
|
|
|
|
#include "unitree_go/msg/motor_cmd.hpp"
|
|
|
|
#include "unitree_go/msg/bms_cmd.hpp"
|
|
|
|
#include "common/motor_crc.h"
|
|
|
|
|
|
|
|
#include "rclcpp/rclcpp.hpp"
|
|
|
|
#include "sensor_msgs/msg/imu.hpp"
|
|
|
|
#include "sensor_msgs/msg/joint_state.hpp"
|
|
|
|
#include "sensor_msgs/msg/temperature.hpp"
|
|
|
|
#include "sensor_msgs/msg/battery_state.hpp"
|
|
|
|
#include "geometry_msgs/msg/twist_stamped.hpp"
|
2024-02-23 02:36:27 +08:00
|
|
|
#include "geometry_msgs/msg/twist.hpp"
|
2024-02-09 01:47:33 +08:00
|
|
|
#include "nav_msgs/msg/odometry.hpp"
|
|
|
|
#include <tf2/LinearMath/Quaternion.h>
|
|
|
|
|
|
|
|
|
|
|
|
// headers needed for highlevel control
|
|
|
|
#include "unitree_go/msg/sport_mode_state.hpp"
|
|
|
|
#include "unitree_api/msg/request.hpp"
|
|
|
|
#include "common/ros2_sport_client.h"
|
2024-02-09 11:14:54 +08:00
|
|
|
#include "joystick.h"
|
2024-04-16 12:05:02 +08:00
|
|
|
#include "unitree_api/msg/request.hpp"
|
2024-02-09 01:47:33 +08:00
|
|
|
class Custom: public rclcpp::Node
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Custom() : Node("go2py_bridge_node")
|
|
|
|
{
|
2024-02-09 11:50:29 +08:00
|
|
|
watchdog_timer = this->create_wall_timer(std::chrono::milliseconds(10), std::bind(&Custom::watchdog, this));
|
2024-02-09 01:47:33 +08:00
|
|
|
pub_odom = this->create_publisher<nav_msgs::msg::Odometry>("/go2/odom", 1);
|
|
|
|
pub_imu = this->create_publisher<sensor_msgs::msg::Imu>("/go2/imu", 1);
|
|
|
|
pub_joint = this->create_publisher<sensor_msgs::msg::JointState>("/go2/joint_states", 1);
|
|
|
|
sub_twist = this->create_subscription<geometry_msgs::msg::TwistStamped>("/go2/twist_cmd", 1, std::bind(&Custom::twistCmdCallback, this, std::placeholders::_1));
|
2024-02-23 02:36:27 +08:00
|
|
|
nav2_twist = this->create_subscription<geometry_msgs::msg::Twist>("/go2/cmd_vel", 1, std::bind(&Custom::nav2TwistCmdCallback, this, std::placeholders::_1));
|
2024-02-09 01:47:33 +08:00
|
|
|
|
|
|
|
// Go2 highlevel subscriber and publishers
|
|
|
|
// the state_suber is set to subscribe "sportmodestate" topic
|
2024-05-05 02:03:03 +08:00
|
|
|
highstate_suber = this->create_subscription<unitree_go::msg::SportModeState>(
|
|
|
|
"sportmodestate", 10, std::bind(&Custom::highstate_callback, this, std::placeholders::_1));
|
2024-02-09 01:47:33 +08:00
|
|
|
// the req_puber is set to subscribe "/api/sport/request" topic with dt
|
2024-05-01 10:32:27 +08:00
|
|
|
highreq_puber = this->create_publisher<unitree_api::msg::Request>("/api/sport/request", 1);
|
2024-02-09 01:47:33 +08:00
|
|
|
|
|
|
|
//Go2 lowlevel interface
|
|
|
|
init_lowcmd();
|
2024-05-05 02:03:03 +08:00
|
|
|
lowstate_suber = this->create_subscription<unitree_go::msg::LowState>(
|
|
|
|
"lowstate", 1, std::bind(&Custom::lowstate_callback, this, std::placeholders::_1));
|
2024-02-09 09:32:03 +08:00
|
|
|
|
2024-05-05 02:03:03 +08:00
|
|
|
lowcmd_suber = this->create_subscription<go2py_common::msg::Go2pyLowCmd>(
|
2024-02-09 09:32:03 +08:00
|
|
|
"/go2/lowcmd", 1, std::bind(&Custom::lowcmd_callback, this, std::placeholders::_1));
|
|
|
|
|
2024-05-01 10:32:27 +08:00
|
|
|
lowcmd_puber = this->create_publisher<unitree_go::msg::LowCmd>("/lowcmd", 1);
|
|
|
|
api_publisher = this->create_publisher<unitree_api::msg::Request>("/api/robot_state/request", 1);
|
2024-05-05 02:03:03 +08:00
|
|
|
status_publisher = this->create_publisher<go2py_common::msg::Go2pyStatus>("/go2py/status", 1);
|
2024-02-09 01:47:33 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
private:
|
2024-02-09 11:50:29 +08:00
|
|
|
rclcpp::TimerBase::SharedPtr watchdog_timer;
|
|
|
|
void watchdog();
|
2024-02-09 01:47:33 +08:00
|
|
|
// Highlevel twist command through standard ROS2 message type
|
|
|
|
void twistCmdCallback(const geometry_msgs::msg::TwistStamped::SharedPtr msg);
|
2024-02-23 02:36:27 +08:00
|
|
|
void nav2TwistCmdCallback(const geometry_msgs::msg::Twist::SharedPtr msg);
|
2024-02-09 01:47:33 +08:00
|
|
|
geometry_msgs::msg::TwistStamped twist_cmd;
|
2024-02-23 02:36:27 +08:00
|
|
|
geometry_msgs::msg::Twist twist;
|
2024-02-09 01:47:33 +08:00
|
|
|
rclcpp::Subscription<geometry_msgs::msg::TwistStamped>::SharedPtr sub_twist;
|
2024-02-23 02:36:27 +08:00
|
|
|
rclcpp::Subscription<geometry_msgs::msg::Twist>::SharedPtr nav2_twist;
|
2024-02-09 01:47:33 +08:00
|
|
|
uint64_t last_highcmd_stamp = 0;
|
|
|
|
|
|
|
|
// ROS2 standard joint state, IMU, and odometry publishers
|
|
|
|
rclcpp::Publisher<sensor_msgs::msg::Imu>::SharedPtr pub_imu;
|
|
|
|
rclcpp::Publisher<sensor_msgs::msg::JointState>::SharedPtr pub_joint;
|
|
|
|
rclcpp::Publisher<nav_msgs::msg::Odometry>::SharedPtr pub_odom;
|
|
|
|
|
|
|
|
// Highlevel interface
|
|
|
|
void highstate_callback(unitree_go::msg::SportModeState::SharedPtr data);
|
|
|
|
rclcpp::Subscription<unitree_go::msg::SportModeState>::SharedPtr highstate_suber;
|
|
|
|
rclcpp::Publisher<unitree_api::msg::Request>::SharedPtr highreq_puber;
|
|
|
|
unitree_api::msg::Request highreq; // Unitree Go2 ROS2 request message
|
|
|
|
SportClient sport_req;
|
|
|
|
|
|
|
|
// Lowlevel interface
|
|
|
|
void lowstate_callback(unitree_go::msg::LowState::SharedPtr data);
|
2024-05-05 02:03:03 +08:00
|
|
|
void lowcmd_callback(go2py_common::msg::Go2pyLowCmd::SharedPtr data);
|
2024-02-09 01:47:33 +08:00
|
|
|
rclcpp::Subscription<unitree_go::msg::LowState>::SharedPtr lowstate_suber;
|
2024-05-05 02:03:03 +08:00
|
|
|
rclcpp::Subscription<go2py_common::msg::Go2pyLowCmd>::SharedPtr lowcmd_suber;
|
2024-02-09 01:47:33 +08:00
|
|
|
// A struct to store the highlevel states for later use
|
|
|
|
rclcpp::Publisher<unitree_go::msg::LowCmd>::SharedPtr lowcmd_puber;
|
|
|
|
unitree_go::msg::LowCmd lowcmd_msg;
|
|
|
|
uint64_t last_lowcmd_stamp = 0;
|
2024-02-09 11:14:54 +08:00
|
|
|
xRockerBtnDataStruct _keyData;
|
2024-04-16 12:05:02 +08:00
|
|
|
rclcpp::Publisher<unitree_api::msg::Request>::SharedPtr api_publisher;
|
2024-05-05 02:03:03 +08:00
|
|
|
rclcpp::Publisher<go2py_common::msg::Go2pyStatus>::SharedPtr status_publisher;
|
2024-02-09 01:47:33 +08:00
|
|
|
|
|
|
|
void init_lowcmd()
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int i = 0; i < 20; i++)
|
|
|
|
{
|
|
|
|
lowcmd_msg.motor_cmd[i].mode = 0x01; //Set toque mode, 0x00 is passive mode
|
|
|
|
lowcmd_msg.motor_cmd[i].q = PosStopF;
|
|
|
|
lowcmd_msg.motor_cmd[i].kp = 0;
|
|
|
|
lowcmd_msg.motor_cmd[i].dq = VelStopF;
|
|
|
|
lowcmd_msg.motor_cmd[i].kd = 0;
|
|
|
|
lowcmd_msg.motor_cmd[i].tau = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct {
|
|
|
|
float px;
|
|
|
|
float py;
|
|
|
|
float height;
|
|
|
|
float roll;
|
|
|
|
float pitch;
|
|
|
|
float yaw;
|
|
|
|
float imu_temp;
|
|
|
|
float wx;
|
|
|
|
float wy;
|
|
|
|
float wz;
|
|
|
|
float ax;
|
|
|
|
float qy;
|
|
|
|
float az;
|
|
|
|
float vx;
|
|
|
|
float vy;
|
|
|
|
float foot_force[4];
|
|
|
|
}highstate;
|
2024-02-09 11:50:29 +08:00
|
|
|
int Estop = 0;
|
2024-04-16 12:29:05 +08:00
|
|
|
int sport_mode = 1;
|
2024-02-09 01:47:33 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void Custom::lowstate_callback(unitree_go::msg::LowState::SharedPtr data)
|
|
|
|
{
|
|
|
|
// std::cout << data->tick << std::endl;
|
|
|
|
sensor_msgs::msg::Imu imu;
|
|
|
|
sensor_msgs::msg::JointState joint_state;
|
|
|
|
nav_msgs::msg::Odometry odom_state;
|
|
|
|
|
|
|
|
// Load the IMU message
|
|
|
|
imu.header.stamp=rclcpp::Clock().now();
|
|
|
|
imu.header.frame_id = "imu_link";
|
|
|
|
imu.orientation.w = data->imu_state.quaternion[0];
|
|
|
|
imu.orientation.x = data->imu_state.quaternion[1];
|
|
|
|
imu.orientation.y = data->imu_state.quaternion[2];
|
|
|
|
imu.orientation.z = data->imu_state.quaternion[3];
|
|
|
|
imu.linear_acceleration.x = data->imu_state.accelerometer[0];
|
|
|
|
imu.linear_acceleration.y = data->imu_state.accelerometer[1];
|
|
|
|
imu.linear_acceleration.z = data->imu_state.accelerometer[2];
|
|
|
|
imu.angular_velocity.x = data->imu_state.gyroscope[0];
|
|
|
|
imu.angular_velocity.y = data->imu_state.gyroscope[1];
|
|
|
|
imu.angular_velocity.z = data->imu_state.gyroscope[2];
|
|
|
|
// Load the joint state messages
|
|
|
|
joint_state.header.stamp = imu.header.stamp;
|
|
|
|
joint_state.header.frame_id = "trunk";
|
|
|
|
joint_state.name.push_back("FR_hip_joint");
|
|
|
|
joint_state.name.push_back("FR_thigh_joint");
|
|
|
|
joint_state.name.push_back("FR_calf_joint");
|
|
|
|
|
|
|
|
joint_state.name.push_back("FL_hip_joint");
|
|
|
|
joint_state.name.push_back("FL_thigh_joint");
|
|
|
|
joint_state.name.push_back("FL_calf_joint");
|
|
|
|
|
|
|
|
joint_state.name.push_back("RR_hip_joint");
|
|
|
|
joint_state.name.push_back("RR_thigh_joint");
|
|
|
|
joint_state.name.push_back("RR_calf_joint");
|
|
|
|
|
|
|
|
joint_state.name.push_back("RL_hip_joint");
|
|
|
|
joint_state.name.push_back("RL_thigh_joint");
|
|
|
|
joint_state.name.push_back("RL_calf_joint");
|
|
|
|
|
|
|
|
for(int i=0; i<12; i++)
|
|
|
|
{
|
|
|
|
joint_state.position.push_back(data->motor_state[i].q);
|
|
|
|
joint_state.velocity.push_back(data->motor_state[i].dq);
|
|
|
|
joint_state.effort.push_back(data->motor_state[i].tau_est);
|
|
|
|
}
|
2024-05-05 02:03:03 +08:00
|
|
|
|
2024-02-09 01:47:33 +08:00
|
|
|
pub_joint->publish(joint_state);
|
|
|
|
pub_imu->publish(imu);
|
2024-02-09 11:56:11 +08:00
|
|
|
// Check for emergency stop
|
2024-02-09 11:50:29 +08:00
|
|
|
memcpy(&_keyData, &data->wireless_remote[0], 40);
|
|
|
|
if (_keyData.btn.components.R2 == 1 && _keyData.btn.components.L2 == 1)
|
|
|
|
{
|
|
|
|
Estop = 1;
|
|
|
|
}
|
2024-04-16 12:05:02 +08:00
|
|
|
if ((_keyData.btn.components.L2 == 1 && _keyData.btn.components.A == 1))
|
2024-02-09 11:50:29 +08:00
|
|
|
{
|
|
|
|
Estop = 0;
|
|
|
|
}
|
2024-04-16 12:05:02 +08:00
|
|
|
if ((_keyData.btn.components.L2 == 1 && _keyData.btn.components.L1 == 1))
|
|
|
|
{
|
|
|
|
auto msg = std::make_shared<unitree_api::msg::Request>();
|
|
|
|
// Populate the message fields
|
|
|
|
msg->header.identity.id = 80005;
|
|
|
|
msg->header.identity.api_id = 1001;
|
|
|
|
msg->parameter = "{\"name\":\"sport_mode\",\"switch\":0}";
|
|
|
|
api_publisher->publish(*msg);
|
2024-04-16 12:29:05 +08:00
|
|
|
sport_mode = 0;
|
2024-04-16 12:05:02 +08:00
|
|
|
}
|
|
|
|
if ((_keyData.btn.components.R2 == 1 && _keyData.btn.components.R1 == 1))
|
|
|
|
{
|
|
|
|
auto msg = std::make_shared<unitree_api::msg::Request>();
|
|
|
|
// Populate the message fields
|
|
|
|
msg->header.identity.id = 80005;
|
|
|
|
msg->header.identity.api_id = 1001;
|
|
|
|
msg->parameter = "{\"name\":\"sport_mode\",\"switch\":1}";
|
|
|
|
api_publisher->publish(*msg);
|
2024-04-16 12:29:05 +08:00
|
|
|
sport_mode = 1;
|
2024-04-16 12:05:02 +08:00
|
|
|
}
|
2024-02-09 11:50:29 +08:00
|
|
|
// std::cout << "Estop: " << Estop << std::endl;
|
2024-02-09 01:47:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Custom::highstate_callback(unitree_go::msg::SportModeState::SharedPtr data)
|
|
|
|
{
|
|
|
|
highstate.px = data->position[0];
|
|
|
|
highstate.py = data->position[1];
|
|
|
|
highstate.roll = data->imu_state.rpy[0];
|
|
|
|
highstate.pitch = data->imu_state.rpy[1];
|
|
|
|
highstate.yaw = data->imu_state.rpy[2];
|
|
|
|
for(int i=0; i<4; i++)
|
|
|
|
{
|
|
|
|
highstate.foot_force[i]=data->foot_force[i];
|
|
|
|
}
|
|
|
|
highstate.height = data->body_height;
|
|
|
|
|
|
|
|
nav_msgs::msg::Odometry odom_state;
|
|
|
|
// odometry states published by the onboard high-level controller
|
|
|
|
odom_state.header.stamp = rclcpp::Clock().now();
|
|
|
|
odom_state.header.frame_id = "odom";
|
|
|
|
odom_state.child_frame_id = "base_link";
|
|
|
|
odom_state.pose.pose.position.x = data->position[0];
|
|
|
|
odom_state.pose.pose.position.y = data->position[1];
|
|
|
|
odom_state.pose.pose.position.z = data->body_height;
|
|
|
|
|
|
|
|
|
|
|
|
odom_state.twist.twist.linear.x = data->velocity[0];
|
|
|
|
odom_state.twist.twist.linear.y = data->velocity[1];
|
|
|
|
odom_state.twist.twist.linear.z = data->velocity[2];
|
|
|
|
odom_state.twist.twist.angular.z= data->yaw_speed;
|
|
|
|
double position_R = 0.05;
|
|
|
|
double orientation_R = 0.005;
|
|
|
|
odom_state.pose.covariance = {
|
|
|
|
position_R, 0, 0, 0, 0, 0, // Covariance for position x
|
|
|
|
0, position_R, 0, 0, 0, 0, // Covariance for position y
|
|
|
|
0, 0, position_R, 0, 0, 0, // Covariance for position z
|
|
|
|
0, 0, 0, orientation_R, 0, 0, // Covariance for orientation roll
|
|
|
|
0, 0, 0, 0, orientation_R, 0, // Covariance for orientation pitch
|
|
|
|
0, 0, 0, 0, 0, orientation_R // Covariance for orientation yaw
|
|
|
|
};
|
|
|
|
|
|
|
|
odom_state.twist.covariance = {
|
|
|
|
position_R, 0, 0, 0, 0, 0, // Covariance for position x
|
|
|
|
0, position_R, 0, 0, 0, 0, // Covariance for position y
|
|
|
|
0, 0, position_R, 0, 0, 0, // Covariance for position z
|
|
|
|
0, 0, 0, orientation_R, 0, 0, // Covariance for orientation roll
|
|
|
|
0, 0, 0, 0, orientation_R, 0, // Covariance for orientation pitch
|
|
|
|
0, 0, 0, 0, 0, orientation_R // Covariance for orientation yaw
|
|
|
|
};
|
|
|
|
|
|
|
|
pub_odom->publish(odom_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Custom::twistCmdCallback(const geometry_msgs::msg::TwistStamped::SharedPtr msg)
|
|
|
|
{
|
|
|
|
auto stamp_now = std::chrono::high_resolution_clock::now();
|
|
|
|
last_highcmd_stamp = std::chrono::duration_cast<std::chrono::microseconds>(stamp_now.time_since_epoch()).count();
|
2024-02-09 11:50:29 +08:00
|
|
|
if(Estop == 0)
|
|
|
|
sport_req.Move(highreq, msg->twist.linear.x, msg->twist.linear.y, msg->twist.angular.z);
|
|
|
|
else
|
|
|
|
sport_req.Damp(highreq);
|
|
|
|
|
2024-02-09 01:47:33 +08:00
|
|
|
// Publish request messages with desired body velocity
|
|
|
|
highreq_puber->publish(highreq);
|
|
|
|
}
|
|
|
|
|
2024-02-23 02:36:27 +08:00
|
|
|
void Custom::nav2TwistCmdCallback(const geometry_msgs::msg::Twist::SharedPtr msg)
|
|
|
|
{
|
|
|
|
auto stamp_now = std::chrono::high_resolution_clock::now();
|
|
|
|
last_highcmd_stamp = std::chrono::duration_cast<std::chrono::microseconds>(stamp_now.time_since_epoch()).count();
|
|
|
|
if(Estop == 0)
|
|
|
|
sport_req.Move(highreq, msg->linear.x, msg->linear.y, msg->angular.z);
|
|
|
|
else
|
|
|
|
sport_req.Damp(highreq);
|
|
|
|
|
|
|
|
// Publish request messages with desired body velocity
|
|
|
|
highreq_puber->publish(highreq);
|
|
|
|
}
|
|
|
|
|
2024-05-05 02:03:03 +08:00
|
|
|
void Custom::lowcmd_callback(go2py_common::msg::Go2pyLowCmd::SharedPtr data)
|
2024-02-09 11:50:29 +08:00
|
|
|
{
|
|
|
|
if(Estop == 0)
|
|
|
|
{
|
|
|
|
for(int i=0; i<12; i++)
|
|
|
|
{
|
|
|
|
lowcmd_msg.motor_cmd[i].q = data->q[i]; // Taregt angular(rad)
|
|
|
|
lowcmd_msg.motor_cmd[i].kp = data->kp[i]; // Poinstion(rad) control kp gain
|
|
|
|
lowcmd_msg.motor_cmd[i].dq = data->dq[i]; // Taregt angular velocity(rad/ss)
|
|
|
|
lowcmd_msg.motor_cmd[i].kd = data->kd[i]; // Poinstion(rad) control kd gain
|
|
|
|
lowcmd_msg.motor_cmd[i].tau = data->tau[i]; // Feedforward toque 1N.m
|
|
|
|
get_crc(lowcmd_msg); //Compute the CRC and load it into the message
|
|
|
|
}
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
for(int i=0; i<12; i++)
|
|
|
|
{
|
|
|
|
lowcmd_msg.motor_cmd[i].q = 0.; // Taregt angular(rad)
|
|
|
|
lowcmd_msg.motor_cmd[i].kp = 0.; // Poinstion(rad) control kp gain
|
|
|
|
lowcmd_msg.motor_cmd[i].dq = 0.; // Taregt angular velocity(rad/ss)
|
|
|
|
lowcmd_msg.motor_cmd[i].kd = 0; // Poinstion(rad) control kd gain
|
|
|
|
lowcmd_msg.motor_cmd[i].tau = 0.; // Feedforward toque 1N.m
|
|
|
|
get_crc(lowcmd_msg); //Compute the CRC and load it into the message
|
|
|
|
}
|
|
|
|
}
|
2024-05-01 10:32:27 +08:00
|
|
|
lowcmd_puber->publish(lowcmd_msg); //Publish lowcmd message
|
2024-02-09 11:50:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Custom::watchdog()
|
2024-02-09 01:47:33 +08:00
|
|
|
{
|
2024-02-09 11:50:29 +08:00
|
|
|
if(Estop == 1)
|
2024-02-09 09:32:03 +08:00
|
|
|
{
|
2024-02-09 11:50:29 +08:00
|
|
|
sport_req.Damp(highreq);
|
|
|
|
highreq_puber->publish(highreq);
|
|
|
|
for(int i=0; i<12; i++)
|
|
|
|
{
|
|
|
|
lowcmd_msg.motor_cmd[i].q = 0.; // Taregt angular(rad)
|
|
|
|
lowcmd_msg.motor_cmd[i].kp = 0.; // Poinstion(rad) control kp gain
|
|
|
|
lowcmd_msg.motor_cmd[i].dq = 0.; // Taregt angular velocity(rad/ss)
|
|
|
|
lowcmd_msg.motor_cmd[i].kd = 3; // Poinstion(rad) control kd gain
|
|
|
|
lowcmd_msg.motor_cmd[i].tau = 0.; // Feedforward toque 1N.m
|
|
|
|
get_crc(lowcmd_msg); //Compute the CRC and load it into the message
|
|
|
|
lowcmd_puber->publish(lowcmd_msg); //Publish lowcmd message
|
|
|
|
}
|
|
|
|
lowcmd_puber->publish(lowcmd_msg);
|
2024-02-09 09:32:03 +08:00
|
|
|
}
|
2024-05-05 02:03:03 +08:00
|
|
|
auto msg = std::make_shared<go2py_common::msg::Go2pyStatus>();
|
2024-04-16 12:29:05 +08:00
|
|
|
msg->estop = Estop;
|
|
|
|
msg->sport_mode = sport_mode;
|
|
|
|
status_publisher->publish(*msg);
|
2024-02-09 01:47:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
rclcpp::init(argc, argv); // Initialize rclcpp
|
|
|
|
rclcpp::spin(std::make_shared<Custom>()); // Run ROS2 node which is make share with low_state_suber class
|
|
|
|
rclcpp::shutdown(); // Exit
|
|
|
|
return 0;
|
2024-02-11 12:20:38 +08:00
|
|
|
}
|