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 |