文章目录

  • 服务端(ROS2)
  • 客户端(ROS1)


服务端(ROS2)

#include <memory>
#include <iostream>
#include <sstream>
#include <string>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
#include "rclcpp/rclcpp.hpp"
#include "nav_msgs/msg/odometry.hpp"
#include <sensor_msgs/msg/nav_sat_fix.hpp>

class GNSSSubscriber : public rclcpp::Node
{
public:
  GNSSSubscriber() : Node("GNSS_subscriber"), socket_fd_(-1)
  {
    // 创建TCP服务器端socket
    socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd_ == -1) {
      RCLCPP_ERROR(this->get_logger(), "Failed to create socket.");
      rclcpp::shutdown();
    }

    sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8889);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(socket_fd_, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
      RCLCPP_ERROR(this->get_logger(), "Failed to bind to port 8888.");
      rclcpp::shutdown();
    }

    listen(socket_fd_, 5); // 监听,最多5个等待连接的队列

    // ROS 2 订阅里程计消息
    subscription_ = this->create_subscription<sensor_msgs::msg::NavSatFix>(
      "/gnss_wgs84", 10, std::bind(&GNSSSubscriber::gnss_callback, this, std::placeholders::_1));
  }

  ~GNSSSubscriber()
  {
    if (socket_fd_ != -1) {
      close(socket_fd_);
    }
  }

private:
  void gnss_callback(const sensor_msgs::msg::NavSatFix::SharedPtr msg)
  {
    // 等待并接受一个新连接
    sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_socket = accept(socket_fd_, (struct sockaddr *)&client_addr, &client_len);
    if (client_socket < 0) {
      RCLCPP_ERROR(this->get_logger(), "Failed to accept connection.");
      return;
    }

    // 将里程计消息转换为字符串
    std::ostringstream ss;
    ss << msg->latitude << ", " 
       << msg->longitude << ", " 
       << msg->altitude << ", "
       << static_cast<float>(msg->status.status);
       
    std::string odom_message = ss.str();
    std::cout << "message: " << odom_message << std::endl;
    // 发送里程计消息给客户端
    send(client_socket, odom_message.c_str(), odom_message.size(), 0);

    // 关闭客户端socket
    close(client_socket);
  }

  rclcpp::Subscription<sensor_msgs::msg::NavSatFix>::SharedPtr subscription_;
  nav_msgs::msg::Odometry last_odom_;
  int socket_fd_;
};

int main(int argc, char *argv[])
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<GNSSSubscriber>();
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

客户端(ROS1)

#include "ros/ros.h"
#include "sensor_msgs/NavSatFix.h"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main(int argc, char **argv) {
    // 初始化ROS节点
    ros::init(argc, argv, "gps_publisher");
    ros::NodeHandle nh;

    // 创建一个发布者
    ros::Publisher gps_pub = nh.advertise<sensor_msgs::NavSatFix>("gps_data", 1000);

    ros::Rate loop_rate(1);  // 设置发布频率为1 Hz

    while (ros::ok()) {
        sensor_msgs::NavSatFix msg;

        // 创建客户端套接字
        int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
        if (clientSocket == -1) {
            std::cerr << "Failed to create client socket." << std::endl;
            return 1;
        }

        // 设置服务器地址结构
        sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // 本地回环地址 // 服务器的 IP 地址
        serverAddr.sin_port = htons(8889); // 服务器监听的端口号

        // 连接到服务器
        if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
            std::cerr << "Connection failed." << std::endl;
            close(clientSocket);
            // return 1;
        }

        // std::cout << "Connected to the server." << std::endl;
        // 接收消息
        char buffer[50];
        memset(buffer, 0, sizeof(buffer));
        if (recv(clientSocket, buffer, sizeof(buffer), 0) == -1) {
            std::cerr << "Error receiving message." << std::endl;
        } else {
            std::cout << "Received message from server: " << buffer << std::endl;

            // 定义两个变量来存储解析后的浮点数
            float lat, lon, alt, status;

            // 使用 sscanf 解析字符数组
            if (std::sscanf(buffer, "%f,%f,%f,%f", &lat, &lon, &alt, &status) == 4) {
                // 打印解析结果
                std::cout << "解析后的数据: " << lat << ", " << lon << ", " << alt << ", " << status << std::endl;
                msg.latitude = lat;
                msg.longitude = lon;
                msg.altitude = alt;
                msg.status.status = static_cast<int8_t>(status);
                // 填充协方差矩阵
                msg.position_covariance[0] = 0.02;  // 经度方差
                msg.position_covariance[1] = 0.0;  // 经度与纬度的协方差
                msg.position_covariance[2] = 0.0;  // 经度与高度的协方差

                msg.position_covariance[3] = 0.0;  // 纬度与经度的协方差
                msg.position_covariance[4] = 0.02;  // 纬度方差
                msg.position_covariance[5] = 0.0;  // 纬度与高度的协方差

                msg.position_covariance[6] = 0.0;  // 高度与经度的协方差
                msg.position_covariance[7] = 0.0;  // 高度与纬度的协方差
                msg.position_covariance[8] = 0.02;  // 高度方差
                gps_pub.publish(msg);
            } else {
                // 解析失败
                std::cerr << "解析失败" << std::endl;
            }
        }

        // 关闭客户端套接字
        close(clientSocket);
        // 在这里可以添加一些延时,以避免过于频繁地连接服务器
        sleep(0.1);
        
        ros::spinOnce();
        loop_rate.sleep();
    }

    return 0;
}