学习 ROS Publisher 的编程实现
目标:Publisher 代码的顺利运行
学习内容:
Publisher (话题模型)发布/订阅
如图
发布者的实现
- 初始化ROS节点
- 向ROSMaster注册节点信息,包括发布的画提名和话题中的消息信息
- 创建消息数据
- 按照一定频率发布消息
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
int main(int argc,char **argv)
{
ros::init(argc,argv,"velocity_publisher");//O
ros::NodeHandle n;//O-
ros::Publisher turtle_vel_pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_vel",10);//O-name
ros::Rate loop_rate(100);
int count = 0;
while (ros::ok())
{
geometry_msgs::Twist vel_msg;
vel_msg.linear.x = 0.9;
vel_msg.angular.z = 0.3;
turtle_vel_pub.publish(vel_msg);
ROS_INFO("Publish turtle velocity command[%0.5f m/s , %0.5f rad/s]",
vel_msg.linear.x,
vel_msg.angular.z);
loop_rate.sleep();
}
return 0;
}
队列长度为10 ,表示底层可能不能快速响应发布的频率,此时,就需要有一个队列,将发布的数据存储到这个队列中来,然后不断往外发布,ROS会默认把最早的数据抛弃掉,保留最新的数据,这样就可能有掉帧等情况的出现。
这边有很多大写的字母一开始没注意大写导致编译出了问题,踩坑。
在编译完Publisher代码之后就需要对CMakeList.txt代码进行编译
设置CMakeList.txt中的编译规则
- 设置需要编译的代码和生成的可执行文件
- 设置链接库
add_executable(velocity_publisher src/velocity_publisher.cpp)
添加库的cmake目标依赖关系
例如,可能需要在通过消息生成或动态重新配置库之前生成代码
target_link_libraries(velocity_publisher ${catkin_LIBRARIES})
指定要链接库或可执行目标的库
解释:第一步就是代码的编译,第二步就是代码的链接
ps:这些都可以在CMakeList.txt文件的提示中找到对应的格式;还有python的代码不需要编译!!!
编译运行发布者
在catkin_ws环境下进行编译(如果编译错误有可能是创建learning_toptic时依赖库写错了),切记环境的编译
source devel/setup.bash
订阅者的实现
基本上和发布者的差不多
- 初始化ROS节点
- 订阅所需要的话题
- 循环的等待话题消息,接受到消息后进入回调函数
- 在回调函数中完成消息的处理
#include<ros/ros.h>
#include<turtlesim/Pose.h>
void poseCallback(const turtlesim::Pose::ConstPtr& msg)
{
ROS_INFO("Turtle pose: x:%0.6f,y:%0.6f" , msg->x,msg->y);
}
int main(int argc,char **argv)
{
ros::init(argc,argv,"pose_subscriber");
ros::NodeHandle n;
ros::Subscriber pose_sub=n.subscribe("/turtle1/pose",10,posecallback);
ros::spin();
return 0;
}
接着就是CMakeList.txt的编译
add_executable(pose_subscriber src/pose_subscriber.cpp)
target_link_libraries(pose_subsriber ${catkin_LIBRARIES}
上面需要注意的就是 $ 和 { 之间不需要加空格;
自定义话题消息
-
自定义msg文件
string name
uint8 sex
uint8 age
uint8 unknown = 0
uint8 male = 1
uint8 female = 2 -
在package.xml中添加依赖包
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime<exec_depend> -
在CMakeList.txt添加编译项
-
编译生成文件
在CMakeList.txt文件中的
find_package(… …message_generation)
add_message_files(
FILES Person.msg
)
generate_messages(
DEPENDENCIES std_msgs
)
ps:这里需要注意格式,不然会出错
在catkin_package那行使得
CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs turtlesim有效
并且在后面添加
message_runtime
然后catkin_make
创建发布者代码
#include<ros/ros.h>
#include<learning_topic/Person.h>
int main(int argc,char**argv)
{
ros::init(argc,argv,"person_publisher");
ros::NodeHandle n;
ros::Publisher person_info_pub = n.advertise<learing_topic::Person>("/person_info",10);
ros::Rate loop_rate(1);
int count = 0;
while (ros::ok())
{
learning_topic::Person person_msg;
person_msg.name = "TOM";
person_msg.age = 19;
person_msg.sex = learning_topic::Person::male;
person_info_pub.publish(person_msg);
ROS_INFO("Publish Person Info :name :%s age :%s sex :%d",
person_msg.name.c_str(),
person_msg.age,
person_msg.sex);
loop_rate.sleep();
}
return 0;
}
创建订阅者代码
#include<ros/ros.h>
#include<learning_topic/Person.h>
void personInfoCallback(const learning_topic::Person::ConstPtr& msg)
{
ROS_INFO("Publish Person Info :name :%s age :%s sex :%d",
msg->name.c_str(),msg->age,msg->sex);
}
int main(int argc,char**argv)
{
ros::init(argc,argv,"person_subscribe");
ros::NodeHandle n;
ros::Subscriber person_info_sub = n.subscribe("/person_info",10,personInfoCallback);
ros::spin();
return 0;
}