ros学习记录4 roscpp的使用

5.1 roscpp

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IB6savAI-1591966456237)(/home/swc/.config/Typora/typora-user-images/image-20200601160445663.png)]

ros提供的使用C++和topic,service,param等交互的接口

  • 官方文档

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yMSRsogh-1591966456239)(/home/swc/.config/Typora/typora-user-images/image-20200601160652061.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcatPHD2-1591966456241)(/home/swc/.config/Typora/typora-user-images/image-20200601160723747.png)]

5.1.1 ros::init()

void ros::init()   //解析ross参数,为本node命名

5.1.2 ros::NodeHandle Class (类)

//常用  成员函数
//创建话题的publisher
ros::Publisher advertise(const string& topic,uint32_t queue_size);
//例子
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise(...,...);
pub.publish(msg);
//创建话题的subscriber
ros::Subscribe subscribe(const string& topic,uint32_t queue_size,void(*)(M)); //M是回调函数,处理msg

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spJeyyBb-1591966456243)(/home/swc/.config/Typora/typora-user-images/image-20200601163556216.png)]

5.1.3 ros::master Namespace

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FVEM18V8-1591966456244)(/home/swc/.config/Typora/typora-user-images/image-20200601163845780.png)]

5.1.4 ros::this_node Namespace

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4OHCtrK5-1591966456246)(/home/swc/.config/Typora/typora-user-images/image-20200601165216228.png)]

5.1.5 ros::service Namespce

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mc4APoIJ-1591966456247)(/home/swc/.config/Typora/typora-user-images/image-20200601192523926.png)]

5.1.6 ros::names Namespace

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScE5bgvl-1591966456247)(/home/swc/.config/Typora/typora-user-images/image-20200601192651443.png)]

5.2 topic_demo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4dlttcVk-1591966456248)(/home/swc/.config/Typora/typora-user-images/image-20200601200157201.png)]

1. 创建package

cd ~/tutorial_ws/src
catkin_creat_pkg topic_demo roscpp rospy std_msgs

2. 新建自定义msg

cd topic_demo/
mkdir msg
cd msg
gedit gps.msg

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9RJmt1G5-1591966456249)(/home/swc/.config/Typora/typora-user-images/image-20200601203925895.png)]

catkin_make 会把*.msg文件编译成*.h文件,#include一下就可以使用了

#include "topic_demo/gps.h"

topic_demo::gps msg;

3. talk.cpp

  • .pro文件的写法,主要是加入ros和msg生成的h文件
# topic_demo.pro
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
    talker.cpp

LIBS += \
    -L/usr/local/lib \
    -L/opt/ros/kinetic/lib \
    -lroscpp -lrospack -lpthread -lrosconsole -lrosconsole_log4cxx\
    -lrosconsole_backend_interface -lxmlrpcpp -lroscpp_serialization -lrostime  -lcpp_common  -lroslib -lroslib


HEADERS += \


INCLUDEPATH +=\
/opt/ros/kinetic/include\
/home/swc/tutorial_ws/devel/include/     # 这个就是ros工作空间的/devel/include/
/*talker.cpp*/
#include <iostream>
#include "ros/ros.h"
#include "topic_demo/gps.h"

using namespace std;

int main(int argc,char** argv)
{
    ros::init(argc,argv,"talker");  //初始化,解析参数,命名节点为"talker"
    ros::NodeHandle nh;             //创建句柄,实例化node
    topic_demo::gps msg;            //创建gps消息
    msg.x = 1.0;                    //msg初始化
    msg.y = 1.0;
    msg.state = "working";
    ros::Publisher pub = nh.advertise<topic_demo::gps>("gps_info",1);//创建publisher
    //ros::Publisher pub = nh.advertise<消息格式>("topic名称",queue_size)
    //queue_size表示缓存队列长度,随时发送接收,设置成1这样比较小的数是可以的
    ros::Rate loop_rate(1.0);//ros::Rate是控制循环的一个类,定义循环发布的频率,这里是1Hz
    while(ros::ok())         //ros::ok() 表示只要ros没有关闭,就一直循环
    {
        //模拟数据的变化
        msg.x = 1.03 * msg.x;//以指数增长,每隔1秒
        msg.y = 1.01 * msg.y;
        //输出当前msg,ROS_INFO和printf(),cout 类似
        ROS_INFO("Talker_____:GPS:x = %f,y = %f",msg.x,msg.y); 
        pub.publish(msg);       //发布消息
        loop_rate.sleep();      //根据定义的发布频率,sleep一秒钟
    }
    return 0;
}

4.listener.cpp

/*listener.cpp*/
#include "ros/ros.h"
#include "topic_demo/gps.h"

//topic_demo::gps::ConstPtr也是一个类
//它是一个常指针,指向topic_demo::gps
//回调函数
void gpsCallback(const topic_demo::gps::ConstPtr& msg)
{
    float distance;
    float x = msg->x;
    float y = msg->y;
    distance = sqrt(pow(x,2)+pow(y,2));
    ROS_INFO("Listener_____distance to ogigin:%f,state:%s",distance,msg->state);
}

int main(int argc, char **argv)
{
    ros::init(argc,argv,"listener");
    ros::NodeHandle nh;
    /*
    创建subscribe
    ros::Subscriber sub = nh.subscribe("监听话题名称",消息队列长度,回调函数(指针);
    "监听话题名称":和publisher设置成一样
    消息队列长度,一般消息来了马上就会被处理掉,所以不要设置的太大,除非想对数据进行缓存,延迟处理
    回调函数:处理从"监听话题"上收到的消息
    */
    ros::Subscriber sub = nh.subscribe("gps_info",1,gpsCallback);
    /*
    实际上,没来一个消息,就把它放在队列里,并不是来一个就会自动处理一个,要调用一个spin()函数
    spin()函数,查看当前队列里面有没有消息,有的话,就调用回调函数进行处理,把队列清空,如果队列是空的,就不会处理
    反复调用当前可触发的回调函数,是一个阻塞的函数,执行到这一句,反复查看有没有可执行的回调函数
    还有一个ros::spinOnce()函数,只查看一次有没有可执行的回调函数,如果没有就往下执行
    */
    ros::spin();
    return 0;
}

5.修改CMakeLists.txt和package.xml

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)   # CMAKE版本
project(topic_demo)		        # 项目名称

find_package(catkin REQUIRED COMPONENTS	# 指定依赖
  roscpp
  rospy
  std_msgs
message_generation
)
				
add_message_files(			# 添加自定义的msg
   FILES
gps.msg
)

generate_messages(DEPENDENCIES std_msgs)# 生成msg对应的h文件

catkin_package(CATKIN_DEPENDS roscpp rospy std_msgs message_runtime)# 用于配置ROS和package配置文件和Cmake文件

include_directories(include ${catkin_INCLUDE_DIRS})    # 指定C/C++的头文件路径

add_executable(talker src/talker.cpp)			# 生成可执行目标文件
add_dependencies(talker topic_demo_generate_message_cpp)# 添加依赖,必须有这句来生成msg?
target_link_libraries(talker ${catkin_LIBRARIES})		# 链接

add_executable(listener src/listener.cpp)
add_dependencies(listener topic_demo_generate_message_cpp)
target_link_libraries(listener ${catkin_LIBRARIES})

package.xml 中添加两句

<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>

6.编译运行

catkin_make

rosrun topic_demo talker

rosrun topic_demo listener

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yoPhmdSK-1591966456250)(/home/swc/.config/Typora/typora-user-images/image-20200602104754397.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smiK3T4W-1591966456250)(/home/swc/.config/Typora/typora-user-images/image-20200602104843504.png)]

也可以在qt里面编译运行listener.cpp,效果一样的

查看话题间关系:rqt_graph

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2cxMbsDN-1591966456251)(/home/swc/.config/Typora/typora-user-images/image-20200602104958758.png)]

7.先接收消息,处理之后发出去

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TfCcQURt-1591966456252)(/home/swc/.config/Typora/typora-user-images/image-20200602160219004.png)]

/*listener.cpp*/
#include "ros/ros.h"
#include "topic_demo/gps.h"

topic_demo::gps gps_data;//转存接收到的数据

void gpsCallback(const topic_demo::gps::ConstPtr& msg)
{
    gps_data = *msg;
    gps_data.state = "received";
    float distance;
    float x = msg->x;
    float y = msg->y;
    distance = sqrt(pow(x,2)+pow(y,2));
    //ROS_INFO("Listener_____distance to ogigin:%f,state:%s",distance,msg->state.c_str());
}

int main(int argc, char **argv)
{
    ros::init(argc,argv,"listener");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<topic_demo::gps>("gps_receive",1);
    ros::Subscriber sub = nh.subscribe("gps_info",1,gpsCallback);
    ros::Rate loop_rate(1.0);
    while(ros::ok())
    {
        ros::spinOnce();//要设置成spinOnce(),不然跑不出来
        pub.publish(gps_data);//也可以在回调函数里面pub
	ROS_INFO("publish  success");
        loop_rate.sleep();
    }
    return 0;
}
/*listener2.cpp*/
#include "ros/ros.h"
#include "topic_demo/gps.h"

void gpsCallback(const topic_demo::gps::ConstPtr& msg)
{
    float distance;
    float x = msg->x;
    float y = msg->y;
    distance = sqrt(pow(x,2)+pow(y,2));
    ROS_INFO("Listener2_____distance to ogigin:%f,state:%s",distance,msg->state.c_str());
}

int main(int argc, char **argv)
{
    ros::init(argc,argv,"listener2");
    ros::NodeHandle nh;
    ros::Subscriber sub = nh.subscribe("gps_receive",1,gpsCallback);
    ros::Rate loop_rate(1.0);
    while(ros::ok())
    {
        ros::spin();
	loop_rate.sleep();
    }
    return 0;
}

8.话题名称相关

以下代码显示了常用的话题的声明,我们通过修改话题名称来理解名称的用法。

int main(int argc, char** argv) 		 // 节点主函数
{
    ros::init( argc, argv, "node1"); 		 // 初始化节点
	{
    ros::NodeHandle nh; 				
    // 声明发布者,话题名 = bar
    // 声明节点句柄
    ros::Publisher node1_pub = nh.advertise<std_msg::Int32>("bar" , 10);
	}
}

​ 这里的节点名称是/node1。如果您用一个没有任何字符的相对形式的bar来声明一个发布者,这个话题将和/bar具有相同的名字。

​ 如果以如下所示使用斜杠(/)字符用作全局形式,话题名也是/bar。

ros::Publisher node1_pub = nh.advertise<std_msg::Int32>(“/bar”, 10);
但是,如果使用波浪号(~)字符将其声明为私有,则话题名称将变为/node1/bar。

ros::Publisher node1_pub = nh.advertise<std_msg::Int32>(“~bar”, 10);

这可以按照下表所示的各种方式使用。其中/wg意味着命名空间的修改。这在下面的描述中更详细地讨论。

Node Relative(基本) Global Private
/node1 bar->/bar /bar->/bar ~bar->/node1/bar
/wg/node2 bar->/wg/bar /bar->/bar ~bar->/wg/node2/bar
/wg/node3 foo/bar->/wg/foo/bar /foo/bar->/foo/ba ~foo/bar->/wg/node3/foo/bar

猜你喜欢

转载自blog.csdn.net/qq_33993729/article/details/106723456
今日推荐