ROS智能轮椅项目-C++实现Socket通信功能包的编写

起因是老板接了个医专的可导航智能轮椅,要求写一个软件实现前后左右控制、扫描的地图保存显示,我在中间写了一个socket通信功能包实现接收前后左右指令发布线速度角速度、接收地图展示指令反馈gym图片。

先实现前后左右的功能,首先得了解socket,开启一个服务器,循环等待软件客户端的连接,连接成功后进入客户端读写的函数中,创建ROS节点句柄、消息发布者、话题名和消息类型。之后监听客户端发送的数据并进行数据的判断,初步定为1、2、3、4为前后左右。做完前后左右判断后对相应的线速度角速度进行赋值并发布到话题中。

具体代码:

#include <sstream>
#include "ros/ros.h"
#include "geometry_msgs/Twist.h"
//socket need xx.h
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<iostream>
#include <fstream>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include <unistd.h>
#define BUFFER_SIZE 100

using namespace std;
//文件发送
void SendFile(int m_Client){
    printf("开始发送");
	int haveSend = 0;
	const int bufferSize = 1024;
	char buffer[bufferSize] = {0};
	int readLen = 0;
	string srcFileName = "/home/bn/sanlou.pgm";
	ifstream srcFile;
	srcFile.open(srcFileName.c_str(),ios::binary);
	if(!srcFile){
		return;
	}
	while(!srcFile.eof()){
		srcFile.read(buffer,bufferSize);
		readLen = srcFile.gcount();
        //将char类型数据转化type类型发送给client
        unsigned char *buffer2 = (unsigned char*)buffer;
		send(m_Client,buffer,readLen,0);
		haveSend += readLen;	
	}
	srcFile.close();
	cout<<"send: "<<haveSend<<"B"<<endl;
}

//服务器读写方法
void listen_data(int fd,int id)
{

    //ros::init(argc, argv, "talker");
    // 创建节点句柄
    ros::NodeHandle n;  
    // 创建一个Publisher,发布名为chatter的topic,消息类型为geometry_msgs::Twist
    ros::Publisher vel_pub = n.advertise<geometry_msgs::Twist>("cmd_vel", 1000);
    // 设置循环的频率
    ros::Rate loop_rate(10);
    int count = 0;


    char buffer[BUFFER_SIZE];
    while(1) //一直处于监听客户端信息状态,知道客户端断开或客户端发出退出信息
    {
        printf("client");
        memset(buffer,0,BUFFER_SIZE);
        int len = recv(fd,buffer,BUFFER_SIZE,0);
        if(len > 0) //如果接受到数据,则判断是否为退出信息
        {
            if(strcmp(buffer,"exit\n") == 0)
            {                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                printf("id %d exited.\n",id);
                break;
            }
            printf("ID_%d:%s\n",id,buffer); //输出第N 个用户,输出的信息
            
        
            if (ros::ok())
            {
            // 初始化geometry_msgs类型的消息
            geometry_msgs::Twist vel;
            std::stringstream ss;
            ss << "hello world " << count;
            //msg.data = ss.str();

            //接受1,2,3,4,5.1-4对应控制车体前后左右移动。5对应加载地图上传到软件端
            const char* a = "1";
            const char* b = "2";
            const char* c = "3";
            const char* d = "4";
            const char* e = "5";
            if (strcmp(buffer,a) == 0)
            {
                vel.angular.z = 0;
                vel.linear.x = 1;
                vel.linear.y = 0;

            }
            else if (strcmp(buffer,b) == 0)
            {
                vel.angular.z = 0;
                vel.linear.x = 0;
                vel.linear.y = 1;
            }
            else if (strcmp(buffer,c) == 0)
            {
                vel.angular.z = 1;
                vel.linear.x = 0;
                vel.linear.y = 0;
            }
            else if (strcmp(buffer,d) == 0)
            {
                vel.angular.z = -1;
                vel.linear.x = 0;
                vel.linear.y = 0;
            }
            else if(strcmp(buffer,e) == 0)
            {
               SendFile(fd);
            }
            else
            {
                vel.angular.z = 0;
                vel.linear.x = 0;
                vel.linear.y = 0;
            }


            // 发布消息
            ROS_INFO("%f %f %f", vel.angular.z,vel.linear.x,vel.linear.y);
            vel_pub.publish(vel);

            // 循环等待回调函数
            ros::spinOnce();

            // 按照循环频率延时
            loop_rate.sleep();
            ++count;
            }  
            
        }
        else //接收数据小于0,或等于0 则退出
        {
            printf("clinet %d close!\n",id);
            break;
        }
    //如果服务端需要发送信息,此处添加发送信息
    //memset(buffer,0,BUFFER_SIZE);
    //scanf("%s",buffer);
    //send(fd,buffer,BUFFER_SIZE,0);
    }
    close(fd); //关闭此客户端的连接的socket
}

 

int main(int argc, char **argv)
{
    //printf("weq");

    ros::init(argc, argv, "talker");
    //sleep(1);
    int sockfd,new_fd;
    struct sockaddr_in my_addr; //本地连接socked
    struct sockaddr_in their_addr; //客户端连接socked
    unsigned int numbytes,sin_size;
    char buffer[BUFFER_SIZE];
    static int i=0; //记录连接客户端数目,可以使用数组,结构体等数据类型记录客户端信息(IP,端口等)
    //记录本地信息
    my_addr.sin_family = AF_INET; //IPV4
    my_addr.sin_port = htons(9999); //绑定端口9999,并将其转化为网络字节
    my_addr.sin_addr.s_addr = INADDR_ANY; //指定接收IP为任意(如果指定IP,则只接收指定IP)
    bzero(&(my_addr.sin_zero),0); //最后位置赋0,补位置
    //设置socked
    if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        perror("socket error!\n");
        exit(1);
    }
    //绑定socked
    if((bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr))) < 0)
    {
        perror("bind error!\n");
        exit(1);
    }

    //开启监听,可连接客户端最大为10个
    if(listen(sockfd,10) == -1)
    {
        perror("listen error!\n");
        exit(1);
    }

    printf("打开监听成功!\n");
    //服务端一直运行,等待客户端连接
    while(1)
    {
        sin_size = sizeof(struct sockaddr_in);
        //等待客户端连接,连接后their_addr接收客户端的IP等信息,没有客户端连接,则一直等待
        if((new_fd = accept(sockfd,(struct sockaddr*)(&their_addr),&sin_size)) < 0)
        {
            perror("accept error!\n");
            exit(1);
        }
        //连接成功后,连接客户端数+1
        i++;
        //开启进程运行客户端
        pid_t childid;
        childid = fork(); //fork()函数有两个返回值,0为子进程,-1为错。子进程运行客户端
        if(childid == 0)
        {
            close(sockfd); //子进程中不再需要sockfd去监听,这里释放它,只需要new_fd即可
            listen_data(new_fd,i);
            exit(0);
        }
        //父进程继续执行while,在accept()等待客户端。父进程的socked此时还在运行,没有关闭
        //此处没有设置父进程退出的代码,因为假设服务器一直运行,如果需要服务器自动退出,可设置服务器
        //等待连接的时间,如果一定时间没有客户端连接,可以退出等待,结束
    }
    //所有客户端
    close(sockfd);
    printf("server-------closed.\n");

  return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
AMCL(Adaptive Monte Carlo Localization)是ROS中常用的定位算法,它可以在机器人运动时根据传感器数据进行自适应定位。本文将介绍如何使用C++实现ROS机器人使用amcl功能进行定位。 1. 安装AMCL功能 在终端中输入以下命令,安装AMCL功能和依赖项。 ``` sudo apt-get install ros-kinetic-amcl sudo apt-get install ros-kinetic-move-base-msgs sudo apt-get install ros-kinetic-geometry-msgs ``` 2. 创建ROS 在终端中输入以下命令,创建ROS。 ``` catkin_create_pkg amcl_demo roscpp std_msgs geometry_msgs move_base_msgs ``` 3. 创建ROS节点 在src文件夹中创建amcl_demo.cpp文件,并添加以下代码。 ```cpp #include <ros/ros.h> #include <geometry_msgs/PoseWithCovarianceStamped.h> #include <geometry_msgs/PoseStamped.h> #include <move_base_msgs/MoveBaseAction.h> #include <actionlib/client/simple_action_client.h> typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient; class AmclDemo { public: AmclDemo() { // 订阅AMCL定位结果 amcl_pose_sub_ = nh_.subscribe("/amcl_pose", 1, &AmclDemo::amclPoseCallback, this); // 发布目标点 goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("/move_base_simple/goal", 1); // 连接move_base节点 move_base_client_ = new MoveBaseClient("move_base", true); ROS_INFO("Waiting for move_base action server..."); move_base_client_->waitForServer(); ROS_INFO("Connected to move_base action server"); } private: void amclPoseCallback(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg) { // 获取机器人在地图上的位置 current_pose_ = msg->pose.pose; } void setGoal(double x, double y, double theta) { // 发布目标点 geometry_msgs::PoseStamped goal; goal.header.frame_id = "map"; goal.header.stamp = ros::Time::now(); goal.pose.position.x = x; goal.pose.position.y = y; goal.pose.orientation = tf::createQuaternionMsgFromYaw(theta); goal_pub_.publish(goal); // 发送目标点给move_base节点 move_base_msgs::MoveBaseGoal move_goal; move_goal.target_pose = goal; move_base_client_->sendGoal(move_goal); } ros::NodeHandle nh_; ros::Subscriber amcl_pose_sub_; ros::Publisher goal_pub_; MoveBaseClient *move_base_client_; geometry_msgs::Pose current_pose_; }; int main(int argc, char **argv) { ros::init(argc, argv, "amcl_demo"); AmclDemo amcl_demo; ros::spin(); return 0; } ``` 4. 编译ROS 在终端中输入以下命令,编译ROS。 ``` cd ~/catkin_ws catkin_make ``` 5. 运行ROS节点 在终端中输入以下命令,运行ROS节点。 ``` rosrun amcl_demo amcl_demo ``` 6. 发布目标点 在终端中输入以下命令,发布目标点。 ``` rostopic pub /move_base_simple/goal geometry_msgs/PoseStamped '{header: {stamp: now, frame_id: "map"}, pose: {position: {x: 1.0, y: 1.0, z: 0.0}, orientation: {w: 1.0}}}' ``` 以上就是使用C++实现ROS机器人使用amcl功能进行定位的全部流程。需要注意的是,具体的实现方式需要根据机器人的硬件和软件环境进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值