目录
一 roscpp
1.Client library 是提供ROS编程的库
CL语言包有两种:c++和py。roscpp 执行效率较高,rospy 开发效率较高。
roscpp 是和topic service param timer 交互的一个接口。
roscpp包含的API简介:http://docs.ros.org/api/roscpp/html/
2. 一个简单的topic Demo
两个node,一个发布模拟的GPS消息,一个接收处理。
步骤:
- 建立package
- 自定义的消息格式 msg
- 发布者的源代码 talker.cpp
- 接收者的源代码 listener.cpp
- 修改CMakeLists 和 xml文件
1.建立package
cd ~/catkin_ws/src
catkin_create_pkg topic_demo roscpp rospy std_msgs
2.自定义消息格式msg
cd topic_demo/ && mkdir msg
cd msg && vim gps.msg
gps.msg 文件内容格式如下:
float32 y
float32 x
string state
经过编译过后会出现对应的头文件 ~/catkin_ws/devel/include/topic_demo/gps.h
3.发布者的源代码 talker.cpp
#include <ros/ros.h>
#include <topic_demo/gps.h>
int main(int argc,char** argv)
{
ros::init(argc,argv,"talker"); //解析参数,命名节点(talker是节点名称)
ros::NodeHandle nh; //创建句柄,实例化node
topic_demo::gps msg; //创建msg消息
msg.x=1.0;
mag.y=1.0;
msg.state="working";
/********创建publisher,advertise 模板函数的第一个参数gps_info是发布的topic的名称,第二个参数是先发布到一个队列中(类似缓存?),随发随收,所以队列的长度设为1。********/
ros::Publisher pub= nh.advertise<topic_demo::gps>("gps_info",1);
/*********接下来要周期性循环发布消息*************/
ros::Rate loop_rate(1.0); //定义循环发布的频率,1代表1hz
while(ros::ok())
{
msg.x=1.03* msg.x;
msg.y=1.03* msg.y;
ROS_INFO( "GPS:x=%f,y=%f",msg.x,msg.y); //打印输出当前msg
pub.publish(msg); //发布消息
loop_rate.sleep();
}
return 0;
}
4.接收者的源代码 listener.cpp
#include <ros/ros.h>
#incldue <topic_demo/gps.h>
#include <std_msgs/Float32.h>
void gpsCallback(const topic_demo::gps::ConstPtr & msg) //常指针
{
std_msgs::Float32 distance; //ros自带的Float32类型,为结构体
distance.data=sqrt(pow(msg->x,2),pow(msg->y,2));
ROS_INFO("Distance=%f,state-=%s",distance.data,msg->state.c_str()); //打印输出
}
int main(int argc,char** argv)
{
ros::init(argc,argv,"listener"); //解析参数,命名节点
ros::NodeHandle n;
/**********创建subscriber************/
/********第一个参数是监听的topic的名称,第二个参数是消息队列的长度,第三个是回调函数(指针),用来处理监听到的信息*******/
ros::Subscriber sub=n.subscribe("gps_info",1,gpsCallback);
ros::spin(); //反复查看队列是否有消息,然后调用当前可触发的回调函数,系统呈阻塞状态
return 0;
}
5.改动CMakeLists 和 xml
改动 CMakeLists
改动 xml
6.编译执行
代码工作均已完成,接下来 编译 catkin_make 执行 rosrun
3. 一个简单的ServiceDemo
两个node,一个发布请求(格式自定义,本例中是姓名和年龄),一个接收处理并返回信息(本例中是一个字符串)。
步骤:
- 建立package
- 定义srv
- 响应者的源代码 server.cpp
- 请求者的源代码 client.cpp
- 修改CMakeLists 和 package.xml文件
1.创建package
cd ~/catkin_ws/src
catkin_create_pkg service_demo roscpp rospy std_msgs
2.定义srv
cd service_demo/
mkdir srv
vim Greeting.srv
编译后会在指定文件下出现头文件,具体如下
3.响应者的源代码 server.cpp
#include <ros/ros.h>
#include <service_demo/Greeting.h>
//返回值为布尔型,表示函数是否被正确执行
bool handle_function(service::demo::Greeting::Request & req, service::demo::Greating::Response &res)
{
ROS_INFO("Request from %s with age %d", req.name.c_str(),req.age); //打印请求信息
res.feedback=“Hi” + req.name +“I am server!”; //处理请求,结果写入reponse
return ture; //返回 true ,正确处理请求
}
int main()
{
ros::init(argc,argv, "greetings_server"); //解析参数,命名节点
ros::NodeHandle nh; //创建句柄,实例化node
/********提供服务,第一个参数是服务名称,第二个参数是处理函数(函数指针)*********/
ros::ServcieServer service = nh.advertiseService(“greetings”, handle_function)
ros::spin();
return 0;
}
4.请求者的原代码
#include <ros/ros.h>
#include <service_demo/Greeting.h>
int main(int argc, char** argv)
{
ros::init(argc,argv,"greetings_server");
ros::NodeHandle nh;
/*******这步是创建client,发送的请求的类型是servcie_demo::Greeting,函数的参数“greetings”就是要发送到的sevice********/
ros::ServiceClient client= nh.serviceClient<servcie_demo::Greeting>("greetings");
service_demo::Greeting srv;
srv.request.name = "HAN" ;
srv.request.age = 20;
/*********client.call返回的布尔值变量也是handle_function返回的结果*************/
if(client.call(srv))
{
ROS_INFO("Feedback from server:%s",srv.response.feedback);
}
else
{
ROS_ERROR("Failed to call service greeting.");
return 1;
}
return 0;
}
5.修改 CMakeList 和 xml
类比之前的。。。
4. 一个简单的Param Demo
同一个功能两套API:ros::param 和 ros::NodeHandle
param_demo.cpp ()在源代码中设置参数
#incldue <ros/ros.h>
int main(int argc, char** argv)
{
ros::init(argc,argv,"greetings_server");
ros::NodeHandle nh;
int parameter1,parameter2,parameter3,parameter4,parameter5;
//获取参数的三种方法, param 是namespace
ros::param::get("param1",parameter1); //把第一个参数(key)的值赋给第二个参数
nh.getParam("param2",parameter2); //把第一个参数(key)的值赋给第二个参数
nh.param("param3",parameter3,123); //如果没有找到param3,就赋给默认值123
//设置参数
ros::param::set("param4",parameter4)
nh.setParam("param5",parameter5)
//检查参数是否存在
ros::param::has("param5")
nh.hasParam("param6");
//删除参数
ros::param::del("param5");
ros::deleteParam("param6");
return 0;
}
另一种设置参数的方法 launch文件法
param_demo_cpp.launch
<launch>
<!--Param标签设置单个参数-->
<param name="param1" value="1" />
<param name="param2" value="2" />
<param name="robot_description" command="$(find xacro)/xacro.py $(find demo)/urdf/robot.urdf" />
<!--rosparam标签设置多个参数-->
<rosparam>
param3:3
param4:4
param10:helloworld!
</rosparam>
<rosparam file= "$(find param_demo)/config/myparam.yaml" command= "load" />
<node pkg= "param_demo" type="param_demo" name="param_demo" output= "screen" />
</launch>