ROS 下实现相机图像采集与图像传输到服务器,socket图传

2023-05-16

前言

        本文介绍一种Qt下进行ROS开发的完美方案,同时给出一个使用TCPROS进行图像传输的一个例子,使用的是ros-industrial的Levi-Armstrong在2015年12月开发的一个Qt插件ros_qtc_plugin,这个插件使得Qt“新建项目”和“新建文件”选项中出现ROS的相关选项,让我们可以直接在Qt下创建、编译、调试ROS项目,也可以直接在Qt项目中添加ROS的package、urdf、launch,感谢Levi-Armstrong。目前这个插件还在不断完善,有问题或者其他功能建议可以在ros_qtc_plugin的项目主页的讨论区提出。

本文是用的操作系统是ubuntu kylin 14.04中文版,ROS版本是indigo,Qt版本是Qt5.5.1(Qt Creator 4.0.3)

本文地址:http://blog.csdn.net/u013453604/article/details/52186375
视频教程:ros_qtc_plugin插件作者Levi-Armstrong录制的插件使用教程
参考:
ROS wiki IDEs
1. Setup ROS Qt Creator Plug in
2. Setup Qt Creator for ROS
3. Debugging Catkin Workspace
4. Where to find Qt Creator Plug in Support
github ros-industrial/ros_qtc_plugin项目主页
插件使用问题

第一部分、入门

一、开发环境准备

//安装开发插件ros_qtc_plugin

//安装方法见历史博客【传送门】

二、新建ROS功能包与节点及编译测试

//查看我的历史博客【 传送门】


三、demo练手

3.1图像发布节点

3.1.1具体代码及解析

#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "img_pub");
  ros::NodeHandle nh;
  image_transport::ImageTransport it(nh);
  image_transport::Publisher pub = it.advertise("camera/image",1);

  cv::Mat image = cv::imread(argv[1],CV_LOAD_IMAGE_COLOR);
  sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(),"bgr8",image).toImageMsg();

  ros::Rate loop_rate(5);
  while(nh.ok())
  {
    pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }

  ROS_INFO("Hello world!");
}

3.1.2修改cmakeList.txt文件

    添加以下代码,然后回到工作空间,执行catkin_make

  • find_package
find_package(catkin REQUIRED COMPONENTS
  cv_bridge
  roscpp
  rospy
  std_msgs
  image_transport
)
#find_package(OpenCV)   #这里我注销了好像也没有报错
  • 添加头文件包含
include_directories(
# include
  ${OpenCV_INCLUDE_DIRS}
  ${catkin_INCLUDE_DIRS}
)

  • 生成可执行文件
add_executable(img_pub src/img_pub.cpp)
  • 连接到库文件
target_link_libraries(img_pub
    ${catkin_LIBRARIES}
  #  ${OpenCV_LIBRARIES}  #这里我注销了好像也没有报错
)

3.1.3修改package.xml文件

package.xml文件中存放的是创建功能包时候节点所依赖的其他功能包,如果创建时候没有添加,则必须在这里手动添加。同时,在cmakeList.txt文件中添加以下内容。关于package.xml文件的具体讲解戳这里:https://www.cnblogs.com/qixianyu/p/6669687.html。

find_package(catkin REQUIRED COMPONENTS
  cv_bridge
  roscpp
  rospy
  std_msgs
  image_transport
)

//博主把这两句删了catkin_make也还是能够通过,先不加,如果报错再改

  <build_depend>opencv2</build_depend>
  <build_depend>image_transport</build_depend>

  <exec_depend>image_transport</exec_depend>
  <exec_depend>opencv2</exec_depend>

3.1.4编译

点击qtcreator左下角的小锤子,开始编译,如果有错误就会在下方显示,双击跳转到出错位置

发现是需要在cmakeList.txt文件中添加

find_package(catkin REQUIRED COMPONENTS
  image_transport
)
注意,在构建自己的功能包的时候如果依赖了其他功能包,必须在find_package中添加依赖的包名。添加这句话后重新编译。

3.2图像订阅节点

3.2.1具体代码及分析

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>

void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
  try
  {
    cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
  }
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "img_listener");
  ros::NodeHandle nh;
  cv::namedWindow("view");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  image_transport::Subscriber sub = it.subscribe("/test/image",1,imageCallback);
  ros::spin();
  cv::destroyWindow("view");

  return 0;
}

3.2.2修改cmakeList.txt和package.xml文件

这个文件中没有使用其他依赖功能包,所以package.xml文件暂时不需要做其他修改

cmakeList.txt文件中需要做一些修改:添加

  • 链接库文件
target_link_libraries(img_listener
    ${catkin_LIBRARIES}
  # ${OpenCV_LIBRARIES}
)
  • 生成可执行文件
add_executable(img_listener src/img_listener.cpp

3.2.3代码编译

查阅资料发现,可以在~/.bashrc中添加如下代码,创建快捷方式cw,cs,cm。分别执行' command'中的命令

#ROS alais command
alias cw='cd ~/Travel_Assistance_Robot'
alias cs='cd ~/Travel_Assistance_Robot/src'
alias cm='cd ~/Travel_Assistance_Robot && catkin_make'

3.3执行

rosrun image_trans img_pub cal.png

然后可以查看话题,发现有我们自己发布的/test/image的话题

rosrun image_trans img_listener

显示图像


3.4 话题关系查看与节点关闭

3.4.1节点交互

为了查看话题之间的关系,我们可以使用rgt_graph指令查看

rosrun rqt_graph rqt_graph

3.4.2节点关闭

想要优雅的关掉节点,请使用rosnode kill命令。当然你使用ctrl+c或者直接关闭终端也可以关闭节点,但这种方法不免过于简单粗暴,而且并未完全的关闭节点,因为节点管理器那里仍然有记录


参考资料

[1]http://wiki.ros.org/image_transport/Tutorials

[2]http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28c%2B%2B%29

[3]https://blog.csdn.net/github_30605157/article/details/50990493

[4]https://blog.csdn.net/xiaocainiaoshangxiao/article/details/13295625

*****************************************我是萌萌哒的分割线***************************************************


第二部分、实战

一、图像采集节点

//2.1、启动相机launch文件

//2.2、相机启动launch文件阅读,代码阅读,调试

//节点间功能的切换

roslaunch ueye_cam rgb8.launch 

打开相机后,显示如下


二、图像显示节点

   这个就是上面的话题监听节点,定时从指定话题获取图像


三、图像传输节点

//节点上的图像传输到服务器上

        我们需要基于校园网来传输图像,两个不同的设备连接在校园网上。问题是校园网上的节点有很多,当机器人移动到不同的位置的时候,所处的节点变化,IP地址也发生变化,此时如何和服务器进行通信?校园网采用了动态IP地址分配方式DHCP。一旦连接上校园网,只要不断开IP地址不应该不变吗?

        TCP/IP的话,客户端需要指定服务器的IP地址,服务器端需要知道客户端的IP地址。然后建立三次握手连接和关闭连接(四次握手)。

校园网的的IP地址一般都是和MAC地址绑定的,就好比路由器中的静态地址保留功能,但是也有例外,有的是动态的分配,每次登陆,都会随机的分配。这个要看学校的实际情况,如果学校是动态分配的,那改成静态的IP地址是没法上网的,也有可能造成IP地址冲突。

需要解决的问题:如何获取动态分配DHCP的地址?目前发现有这种方式:

  • 安装arp-scan工具[在github上下载最新版本,否则有些获取不到主机名],使用rp-scan工具扫出局域网所有的IP地址

arp协议是一个数据链路层协议,负责IP地址和Mac地址的转换。

sudo apt-get arp-scan

通过硬件地址筛选

 sudo arp-scan --interface=wlan0 --localnet | grep 54:35:30:19:68:8f

en0是网卡的设备名称,可以通过ifconfig命令获得,有多种网卡时注意不要写错

当我的IP为 inet addr:10.88.60.14时候,通过该方式只能够查到10.88网络上的主机列表,而看不到其他网络上的主机列表。比如看不到10.95网络上的主机列表。10.95.6.210。

  • 在学校申请固定IP地址【赵海武】,那电脑每次开机IP地址会发生改变吗?

3.1、客户端图像发送程序

3.1.1、TX2上图像传输节点,从指定话题上获取消息,传输图像

https://blog.csdn.net/hanshuning/article/details/50581725

使用装有ROS插件的qtcrreator来调试。这里需要先设置一下:

点击左边的带三角的run,在右边add attach to node,选择需要调试的节点;同时,add run step,运行需要运行的节点


然后就可以happy的调试了。

F5执行

F9设置断点

F10跳过,执行下一步指令

F11进入,具体实现调试

注意:这里有一个小坑,就是工程代码里面切记不要有中文,否则调试时候会进入汇编代码中,如下图所示:


设置断点后调试,直接进入了汇编代码界面

因为我的代码有中文路径:

改成全英文路径,重新调试即可:


3.1.2、读取本地图片,并发送

(client)

/*socket image transfer
* 2018.5.10
* wzw
* qt head**************************/
#include <QCoreApplication>
#include <QDebug>

//socket headfile
#include <netinet/in.h>    // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>    // for socket
#include <stdio.h>        // for qDebug
#include <stdlib.h>        // for exit
#include <string.h>        // for bzero
#include <time.h>                //for time_t and time
#include <arpa/inet.h>
#include <unistd.h>    //close(client_socket);

//opencv headfile
#include <vector>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using  namespace cv;
using  namespace std;

#define HELLO_WORLD_SERVER_PORT   7754
#define BUFFER_SIZE 1024

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug("test ok");
    //get server ip addr
    if (argc != 2)
    {
        qDebug("Usage: %s ServerIPAddress\n",argv[0]);
        exit(1);
    }
    qDebug("ServerIPAddress %s\n",argv[1]);

    /**************
     * socket struct
     * ***********/
    //设置一个socket地址结构client_addr,代表客户机internet地址, 端口
    struct sockaddr_in client_addr;
    bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
   // memset(&client_addr,sizeof(client_addr));
    client_addr.sin_family = AF_INET;    //internet协议族
    client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址
    client_addr.sin_port = htons(0);    //0表示让系统自动分配一个空闲端口

    /*****
     * socket descriptor
     * 创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
     * ****/
    int client_socket = socket(AF_INET,SOCK_STREAM,0);
    if( client_socket < 0)
        {
            qDebug("Create Socket Failed!\n");
            exit(1);
        }

    /******
     * bind port
     * 把客户机的socket和客户机的socket地址结构联系起来,zhiding client_socket ip,point to addr
     * *******/
    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
        {
            qDebug("Client Bind Port Failed!\n");
            exit(1);
        }

    /*****
     * get server addr from argv[1],
     * set server params
     * 设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
     * server_addr.sin_addr.s_addr=inet_addr(argv[1]);//same as up inet_aton
     * ****/
    //
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    if(inet_aton(argv[1],&server_addr.sin_addr) == 0)
        {
            qDebug("Server IP Address Error!\n");
            exit(1);
        }
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    socklen_t server_addr_length = sizeof(server_addr);
    /***
     * connect request,to server ip.success return 0;fail is 1
     * 向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
     * **/
     if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)
        {
            qDebug("Can Not Connect To %s!\n",argv[1]);
            exit(1);
        }
    qDebug("success connect To %s!\n",argv[1]);

    /*********************  data transfer test  ****************************/
    /*****
     * data prepare,set buffer
     * bzero == memset
     * ****/
    char buffer[BUFFER_SIZE];
    bzero(buffer,BUFFER_SIZE);
    //从服务器接收数据到buffer中
    int length = recv(client_socket,buffer,BUFFER_SIZE,0);
    if(length < 0)
        {
            qDebug("Recieve Data From Server %s Failed!\n", argv[1]);
            exit(1);
        }
    qDebug("\n%s\n",buffer);
    bzero(buffer,BUFFER_SIZE);
    // 向服务器发buffer中的数据
    bzero(buffer,BUFFER_SIZE);
    strcpy(buffer,"Hello, World! From Client\n");
    int send_flag=send(client_socket,buffer,BUFFER_SIZE,0);
    if(!send_flag)
        qDebug("send error\n");
    qDebug("send success\n");

    /********************* 向服务器发送image  ****************************/
    //1.load image,get imagesize
    Mat s_img=imread("1.jpg");
    imshow("s_img",s_img);
    vector<uchar> encode_img;
    imencode(".jpg", s_img, encode_img);//
    /****
     * test
     * ************/
    // align value
    /*
    Mat test_img(650,552,CV_8UC3);
    uchar* pxvec=test_img.ptr<uchar>(0);
    int i,j;
    for(i=0;i<s_img.rows;i++)
    {
        pxvec = test_img.ptr<uchar>(i);
        // 3 channels range,BGR
        for(j=0;j<s_img.cols*s_img.channels();j++)
        {
            pxvec[j]=244;
        }
    }

    imshow("test_img",test_img);
    imshow("s_img_encode",s_img);
*/
    //s_img-->vector
    /*
    int i,j;
    uchar* pxvec = s_img.ptr<uchar>(0);
    for(i=0;i<s_img.rows;i++)
    {
        pxvec = s_img.ptr<uchar>(i);
        // 3 channels range,BGR
        for(j=0;j<s_img.cols*s_img.channels();j++)
        {
            //qDebug("px value is %d",pxvec[j]) ;
            encode_img.push_back(pxvec[j]);
        }
    }
    */
    //get send_buffer
    int encode_img_size=encode_img.size();
    int s_img_size=s_img.rows*s_img.cols*3;
    qDebug("filesize is %d,width*hight*3 is %d\n",encode_img_size,s_img_size);

    uchar* send_buffer=new uchar[encode_img.size()];
    copy(encode_img.begin(),encode_img.end(),send_buffer);

    //2.send file_name
    int toSend=encode_img_size, receive  = 0, finished = 0;
    QString photoName;
    char* file_name;
    char char_len[10];
    photoName=QString("1.jpg");
    file_name=photoName.toLatin1().data();
    // file_name,qDebug file_name be empty
    //qDebug("file name is %s\n",file_name);
    bzero(buffer,BUFFER_SIZE);
    send_flag=send(client_socket, file_name, 10, 0);
    if(!send_flag)
      {
        qDebug(" send file_name failed\n ");
        exit(1);
      }
    qDebug("success send file_name \n");
    //3.send image length
    sprintf(char_len, "%d", toSend);
    send(client_socket, char_len, 10, 0);//hello world!!hei hei(xiao)!!  strlen(char_len)这里要写一个固定长度,然后让服务器端读出一个固定长度,否则会出错
    qDebug("char_len is %s\n",char_len);

    // send test

    //4.send image data
    while(toSend  >  0)
    {
        int size = qMin(toSend, 1000);//以前是1000
        if((receive = send(client_socket, send_buffer + finished, size, 0)))  //send wenzi
        {
            if(receive==-1)
            {
                printf ("receive error");
                break;
            }
            else
            {
                toSend -= receive;// shengxia de unsend
                finished += receive; //sended
            }
        }
    }

    //5.close socket
    close(client_socket);
    qDebug("close socket\n");
    return a.exec();
}

(server)

#include <QCoreApplication>
//本文件是服务器的代码
#include <netinet/in.h>    // for sockaddr_in
#include <sys/types.h>    // for socket
#include <sys/socket.h>    // for socket
#include <stdio.h>        // for QDebug
#include <stdlib.h>        // for exit
#include <string.h>        // for bzero
#include <time.h>                //for time_t and time
#include <unistd.h>
//#include <printf>

#define HELLO_WORLD_SERVER_PORT 7754
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    //服务器代码
    ///

    //设置一个socket地址结构server_addr,代表服务器internet地址, 端口
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
    char file_name[10] = "25.jpg";
    char* file_buffer = new char[552 * 650 * 3];


    //创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
    int server_socket = socket(AF_INET,SOCK_STREAM,0);
    if( server_socket < 0)
        {
            printf("Create Socket Failed!");
            exit(1);
        }

    //把socket和socket地址结构联系起来
    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
        {
            printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT);
            exit(1);
        }

        listen(server_socket, LENGTH_OF_LISTEN_QUEUE);

    while (1) //服务器端要一直运行
    {

        struct sockaddr_in client_addr;
        socklen_t length = sizeof(client_addr);
        //accept() kai shi jie shou shu ju
        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
        if ( new_server_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }

        char buffer[BUFFER_SIZE];
        bzero(buffer, BUFFER_SIZE);

        //send hello world
        strcpy(buffer,"Hello,World! 从服务器来!");
        strcat(buffer,"\n"); //C语言字符串连接

        send(new_server_socket,buffer,BUFFER_SIZE,0);

        bzero(buffer,BUFFER_SIZE);
        //接收客户端发送来的信息到buffer中
        length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
        printf("%s\n",buffer);
        printf("regional file_name is %s\n",file_name);
        recv(new_server_socket, file_name, 10, 0);
        printf("received file_name is %s\n", file_name);

        char char_len[10];
        long file_length,read_length;
        char directory[100] = "/home/sa/abc/";
        int finished = 0;

        recv(new_server_socket, char_len, 10, 0);
        read_length = atoi(char_len);
        file_length = read_length;
        printf("received file_length is %d\n", read_length);

        while (read_length > 1000)
        {
            int receive = recv(new_server_socket, file_buffer + finished, 1000, 0);
            //strcpy(file_buff, buff);
            read_length -= receive;
            finished += receive;
        }
        read_length = recv(new_server_socket, file_buffer + finished, 1000, 0);

        FILE* fp = fopen(strcat(directory, file_name), "wb");
        if (fp == NULL)
            printf("create file failed!\n");
        else
        {

            fwrite(file_buffer, 1, file_length, fp);
            fclose(fp);
            printf("create file succed!\n");
        }

        //关闭与客户端的连接
        close(new_server_socket);
    }
    //关闭监听用的socket
    close(server_socket);

    return a.exec();
}

3.1.3从指定话题读取摄像头头像,并按序号保存

/*****
 * sub img from img topic:/camera/image_raw
 * *****/
//qt head

/***
 * ros img headfile
 * ****/
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <iostream>

using namespace std;
/****
 * socket headfile
 * ******/

unsigned int fileNum = 1;
bool imageSaveFlag;
void imageTransCallback(const sensor_msgs::ImageConstPtr& msg)
{
  try
  {
    //imgshow
    cv::imshow("show image", cv_bridge::toCvShare(msg, "bgr8")->image);
    char key;
    key=cv::waitKey(33);
    if(key==32)
      imageSaveFlag=true;
    if(imageSaveFlag)
    {
      stringstream fileName;
      stringstream filePath;
      fileName<<"goal rgbImage"<<fileNum<<".jpg";
      filePath<<"/home/nvidia/Travel_Assistance_Robot/image/"<<fileNum<<".jpg";
      string fn=fileName.str();
      string fp=filePath.str();
      cv::imwrite(fp,cv_bridge::toCvShare(msg, "bgr8")->image);
      imageSaveFlag =false;
      fileNum ++;
      cout<<fileName<<"had saved."<<endl;
    }
    //imgwrite



   //socket image trans

  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
  }
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "img_listener");
  ros::NodeHandle nh;
  cv::namedWindow("show image");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  image_transport::Subscriber sub = it.subscribe("/camera/image_raw",1,imageTransCallback);


  ros::spin();

  cv::destroyWindow("view");

  return 0;
}

3.1.4、结合3.1.1和3.1.2,从指定话题获取图像,并使用socket将图像传输至服务器

//github 

https://github.com/zuwuwang/qt_ros_ws/blob/master/src/guitest/src/socketsend_node.cpp
https://github.com/zuwuwang/qt_ros_ws/blob/master/src/guitest/include/guitest/socketsend_node.hpp

//将获话题消息放到回调函数中

//ROS下定时从节点获取图像

//将socket节点放到回调函数中

vim 查看图像的二进制数据

Vim 可以用来查看和编辑二进制文件
vim -b fileName    加上-b参数,以二进制打开
然后输入命令  :%!xxd -g 1  切换到十六进制模式显示,:wq退出


三、服务器异常检测结果回传

        客户端C++代码发送图像,服务器端用python实现了接收图像,连续接收。然后接收到图像之后,输入到MCNN进行检测,检测结果回传。

// 桑永龙,发送检测结果

参考资料

[1]https://blog.csdn.net/zhuoyueljl/article/details/53557822

[2] 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ROS 下实现相机图像采集与图像传输到服务器,socket图传 的相关文章

  • Java Socket聊天室

    Socket聊天室 1 创建登录判断类UserLogin 2 创建登录服务器LoginServer 3 创建聊天服务器ChatServer 4 创建客户端Client 5 创建服务器用于处理聊天的线程类ChatThread 6 创建客户端C
  • 在Ubuntu 14.04.2 LTS上安装Qt

    Qt是一个跨平台的应用程序框架 广泛用于开发具有GUI界面的应用软件以及命令行工具 几乎所有操作系统都可以使用Qt 如Windows Mac OS X Android等 用于开发Qt应用程序的主要编程语言是C 但是可以使用诸如Python
  • 【小练习】windows与linux进行socket文件传输

    在Windows与Linux使用socket通信基础上 添加文件传输功能 需要进行简单的交互 目录 程序效果 实现流程 样例代码 测试用例 参考资料 程序效果 Windows客户端可以从Linux服务器端索要文件 也可以发送文件至Linux
  • Raspberry Pi 上 ROS 服务器/客户端通过GPIO 驱动硬件

    ROS 服务 现在 想象一下你在你的电脑后面 你想从这个服务中获取天气 你 在你身边 被认为是客户端 在线天气服务是服务器 您将能够通过带有 URL 的 HTTP 请求访问服务器 将 HTTP URL 视为 ROS 服务 首先 您的计算机将
  • C++知识分享: Socket 编程详解,万字长文

    介绍 Socket编程让你沮丧吗 从man pages中很难得到有用的信息吗 你想跟上时代去编Internet相关的程序 但是为你在调用 connect 前的bind 的结构而不知所措 等等 好在我已经将这些事完成了 我将和所有人共享我的知
  • SocketOutputStream和SocketChannel write方法的区别和底层实现

    Java直接内存原理提到了SocketChannel write的实现原理 通过IOUtil write将java堆内存拷贝到了直接内存 然后再把地址传给了I O函数 那么 BIO 是怎么实现往socket里面写数据的呢 BIO Socke
  • 程序“catkin_init_workspace”尚未安装。 您可以使用以下命令安装: sudo apt install catkin

    程序 catkin init workspace 尚未安装 您可以使用以下命令安装 sudo apt install catkin 问题如图 先贴上解决后的效果 运行环境 ubuntu 16 04 ros版本 kinetic 问题解释 这个
  • socket连接超时问题

    一部分 把CSDN与中文yahoo翻了底朝天 也没找到如何设置socket的连接超时的满意方法 问此问题的兄弟已有一大堆 这里偶就讲一下win下如何设置socket的connect超时 设置connect的超时很简单 CSDN上也有人提到过
  • c#Socket 异步通讯(客户端与服务端)

    c Socket 异步通讯 多个客户端与服务端 最近公司有个项目 涉及到的通讯对象有点多 就拿其中一个库的通讯来说就用到了3个PLC 这里就涉及了一个服务器与多个客户端之间的通讯了 同时上位机既需要做客户端 也需要做服务端 因为跟PLC之间
  • 《机器人操作系统入门》课程代码示例安装出错解决方法

    问题描述 学习 机器人操作系统入门 课程时 在Ubuntu 16 04 上安装了kinetic 安装ROS Academy for Beginners时依赖总是报错 如下所示 rosdep install from paths src ig
  • linux send recv函数详解

    2009 05 10 21 55 int send SOCKET s const char FAR buf int len int flags 不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据 客户程序一般用sen
  • 如何将从 rospy.Subscriber 数据获得的数据输入到变量中?

    我写了一个示例订阅者 我想将从 rospy Subscriber 获得的数据提供给另一个变量 以便稍后在程序中使用它进行处理 目前 我可以看到订阅者正在运行 因为当我使用 rospy loginfo 函数时 我可以看到打印的订阅值 虽然我不
  • 无法加载 LZ4 支持的 Python 扩展。 LZ4 压缩将不可用

    我是 ROS 新手 我刚刚打开终端并输入roscore和另一个终端并键入rostopic node我收到这个错误 上面写着 无法加载 LZ4 支持的 Python 扩展 LZ4 压缩将不可用 我搜索并去了https pypi org pro
  • ROS AsyncSpinner 的多线程行为

    我试图了解 ROS 中的 AsyncSpinner 是如何工作的 因为我可能有一些误解 你可以找到类似的问题here As seen here它的定义提到 异步旋转器 产生几个线程 可配置 将并行执行回调 同时不会阻塞执行该操作的线程 叫它
  • 错误状态:平台不允许不安全的 HTTP:http://0.0.0.0:9090

    我正在尝试从我的 flutter 应用程序连接到 ws local host 9090 使用 rosbridge 运行 的 Ros WebSocket 服务 但我在 Flutter 中收到以下错误 错误状态 平台不允许不安全的 HTTP h
  • 如何访问 Heroku 中的 docker 容器?

    我已按照此处构建图像的说明进行操作 https devcenter heroku com articles container registry and runtime getting started https devcenter her
  • ROS安装错误(Ubuntu 16.04中的ROS Kinetic)

    中列出的步骤顺序http wiki ros org kinetic Installat 已被关注 尝试在Ubuntu 16 04中安装ROSkinetic 输入以下命令时出错 sudo apt get install ros kinetic
  • 在 ROS - Python 中使用来自多个主题的数据

    我能够显示来自两个主题的数据 但无法在 ROS 中实时使用和计算这两个主题的数据 用 Python 代码编写 您有想法存储这些数据并实时计算吗 谢谢 usr bin env python import rospy import string
  • 无法在 Ubuntu 20.04 上安装 ROS Melodic

    我正在尝试使用这些命令在 Ubuntu 20 04 上安装 ROS Melodic sudo sh c echo deb http packages ros org ros ubuntu lsb release sc main gt etc
  • 使用 CMake 链接 .s 文件

    我有一个我想使用的 c 函数 但它是用Intel编译器而不是gnu C编译器 我在用着cmake构建程序 我实际上正在使用ROS因此rosmake但基础是cmake所以我认为这更多是一个 cmake 问题而不是ROS问题 假设使用构建的文件

随机推荐

  • 线程如何在底层执行指令?

    一条线程是如何执行的呢 一条线程它有自己独立的栈和pc寄存器 xff0c 寄存器的作用来存储字节码指令地址 xff0c 它来告诉电脑要执行的下一条指令 我们通过main方法反编译出来的代码 xff0c 来详细的探究main线程执行方法中代码
  • 在Linux中如何查看文件的修改日期

    有时候可能需要检查有关文件的详细信息 xff0c 例如文件的修改日期 当你要检查文件的最后编辑时间时 xff0c 本文可能会派上用场 在本文将学习4种方法查看文件的修改日期 使用stat stat 可以显示文件属性的详细信息 xff0c 比
  • 对象的组成

    对象有两种情况 xff1b 普通对象有3部分组成 1 对象头 对象头有两部分 xff1a 1是markword xff0c 2是klass pointer 类型指针 2 示例数据 3 对齐填充 数组对象有4部分组成 1 对象头 对象头有两部
  • 符号引用&直接引用

    符号引用不会加载到虚拟机内存中 xff0c 而直接引用是在内存中的 符号引用 xff1a 在java中 xff0c 一个java类会变编译为字节码文件 xff0c 在编译时 xff0c java类并不知道所引用类的实际地址 也就是直接引用
  • 大端序发送数据

    需要发送数字 151510 大端序发送就是 xff1a 00 02 4F D6 string smallData 61 textBox1 Text 小端数据 if smallData 61 61 34 34 MessageBox Show
  • DSP28335笔记--SCI篇

    采用FIFO来实现数据的发送与接收 xff0c 一般就是指采用FIFO中断 在标准SCI模式下通过中断方式来接收或者发送数据可以发现 xff0c 每接收或者发送一个字符就要进一次中断 xff0c 如果发送的字符比较多的话 xff0c 很明显
  • 无人机实验笔记(2019电赛)

    刚看到题目的时候自然想到的是巡空中电缆线 思路 xff1a 用一个摄像头架高在无人机上 xff0c 与地理坐标Z成一定角度 如图 xff0c 无人机看到的电缆线是实际电缆线在地面上的投影 xff0c 而投影线在 无人机视野的位置 和 无人机
  • [CMake教程](四)CMake 配置生成lib或者so的库文件

    CMake教程 xff08 四 xff09 CMake 配置生成lib或者so的库文件 xff08 1 xff09 系列教程介绍 上面几个教程我们的程序都是生成可执行文件 但是我们在合作开发算法的时候经常需要交付的是一个模块 xff0c 该
  • SLAM问题汇总

    Issue dropped 100 00 of messages so far Resolve tf transform wrong for me change scan to robot1 scan to resolve https an
  • STL基础4:STL7个常用容器的比较

    1 STL容器分类 xff1a STL的容器可以分为以下几个大类 一 顺序 xff08 序列 xff09 容器 xff0c 有vector list deque string stack 适配器类 queue 适配器类 priority q
  • PCB布局技巧

    1 布局前丝印放器件中间 结果 xff1a 布局布线之前 xff0c 把标号位置批量修改到器件中心 丝印既不会阻挡视线 也可以分辨出丝印对应的元件 问题描述 xff1a 在PCB布局时候 xff0c 我们会发现 xff0c 刚导入PCB的元
  • 第四次游戏革命:全息游戏

    最近一个月 xff0c 把国内外十数款单机 网游大作横扫一遍 xff0c 感慨颇多 国内游戏 xff0c 抄袭遍地 xff0c 十足的坑爹 xff0c 浪费青春 反观国外 xff0c 韩国网游经典而耐玩 xff0c C9 43 洛奇英雄传
  • UART, IIC, SCI, SPI, 232, 485, 422, CAN, SDIO, GPIO, MODBUS, TCP/IP汇总简介

    UART IIC SCI SPI 232 485 422 CAN SDIO GPIO MODBUS TCP IP汇总简介 UART xff1a Universal Asynchronous Receiver Transmitter xff1
  • 二维数组的定义

    1 概念 二维数组就是一种数组的数组 xff0c 其本质上还是一个一维数组 xff0c 只是它的数据元素又是一个一维数组 如果你对这个概念想象不出来 xff0c 给大家举个栗子 xff0c 相信吸烟的同学一下子就会明白 一根烟 61 一个变
  • nginx不转发http header问题解决

    文章整理自网络 作者 64 loongshawn xff1a http blog csdn net loongshawn article details 78199977 xff0c 建议读者阅读原文 xff0c 确保获得完整的信息 1 问
  • SimpleFOC(二)—— 快速入门 (开环控制)

    目录 一 硬件介绍 1 驱动板版本说明 2 驱动板跳线 3 硬件准备 4 硬件连接 二 软件操作 1 安装Arduino IDE 2 安装SimpleFOC library 3 打开示例程序 三 电机控制 1 程序下载 2 开环速度控制 3
  • curl参数详解

    原文 xff1a http blog csdn net yanhui wei article details 21530811 cURL可以使用URL的语法模拟浏览器来传输数据 xff0c 因为它是模拟浏览器 xff0c 因此它同样支持多种
  • 嵌入式单片机基础篇(十八)之ILI9341 液晶控制器

    ILI9341 液晶控制器详解 1 ILI9341 液晶控制器简介 xff1a ILI9341 液晶控制器自带显存 xff0c 其显存总大小为 172800 xff08 24032018 8 xff09 xff0c 即 18 位模式 xff
  • LOTO 示波器软件功能演示——RS232串口解码

    LOTO 示波器软件功能演示 RS232串口解码 我们今天演示一下怎么用LOTO示波器对串口进行解码 xff0c 使用了一个USB转串口的设备 xff0c 来产生串口数据 xff0c 用OSCA02 LOTO示波器演示 示波器我们只需要建立
  • ROS 下实现相机图像采集与图像传输到服务器,socket图传

    前言 本文介绍一种Qt下进行ROS开发的完美方案 xff0c 同时给出一个使用TCPROS进行图像传输的一个例子 xff0c 使用的是ros industrial的Levi Armstrong在2015年12月开发的一个Qt插件ros qt