ROS topic
def
ROS Topics are the mechanism used to pass messages between nodes. When a node wants to make information available to other nodes at run-time, it publishes messages to a topic.
Topic 使用的是PUSH模式,采用的是观察者模式,订阅者通过订阅TOPIC获取更新的messages。
publishers 和subsribers 都可以是多个。
实践1
创建单个publisher
如何创建topic,如何创建多个publishers 和多个subsribers
python 创建publisher,python 的好处是只需要修改package.xml文件,不需要修改其他文件
#! /usr/bin/env python
import rospy
from std_msgs.msg import Int32
def talker():
pub = rospy.Publisher('counter', Int32, queue_size=10)
rospy.init_node('publisher', anonymous=True)
rate = rospy.Rate(2) # 10hz
cnt = 0
while not rospy.is_shutdown():
hello_str = "hello world %s" % cnt
rospy.loginfo(hello_str)
pub.publish(cnt)
cnt += 1
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
使用cpp 版本,需要修改cmakelist.txt文件
#include "ros/ros.h"
#include "std_msgs/Int32.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_msgs::Int32>("chatter", 1000);
ros::Rate loop_rate(2);
int count = 0;
while (ros::ok())
{
std_msgs::Int32 msg;
msg.data = count;
chatter_pub.publish(msg);
count++;
//ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
修改cmakelist.txt
add_executable(publisher src/topic_publisher.cpp)
target_link_libraries(publisher ${catkin_LIBRARIES})
add_dependencies(publisher beginner_tutorials_generate_messages_cpp)
增加订阅者
创建单个订阅者
#!/usr/bin/env python
import rospy
from std_msgs.msg import Int32
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %d", data.data)
def listener():
rospy.init_node('topic_subscriber', anonymous=True)
rospy.Subscriber("counter", Int32, callback)
rospy.spin()
if __name__ == '__main__':
listener()
#include "ros/ros.h"
#include "std_msgs/Int32.h"
void chatterCallback(const std_msgs::Int32::ConstPtr& msg)
{
ROS_INFO("I heard: [%d]", msg->data);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("counter", 1000, chatterCallback);
ros::spin();
return 0;
}
创建多个订阅者
因为ROS是通过名称来索引topic,只要定义好topic名称即可。
同样,publisher只要是向同一个名称的topic上发送即可。
创建自定义的message
step1:创建msg文件夹
step2:在msg中定义msg数据类型(所有的设定使用文本形式,如json类型)
step3:在package.xml(属性:依赖关系)添加编译和运行时的约束
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
step4:修改xml文件
#找到编译运行所需要的依赖文件(ros 会把相关的package汇集在一起)
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation)
#添加msg数据类型的定义
add_message_files(
FILES
Num.msg
)
#生成msg
generate_messages(DEPENDENCIES
std_msgs) #如果使用了其他消息类型中的数据类型,需要在这里添加相应的依赖
#在cmake上声明运行时所需要的依赖
catkin_package(
CATKIN_DEPENDS message_runtime …
)
#使用cmake编译生成新的msg
catkin_make install # 安装刚刚生成的msg,这一步很重要,不然容易找不到msg
== 注意添加的顺序,先添加msg文件然后再生成,最后添加运行时的依赖。==
step5:验证是否添加成功
rosmsg show Num
rosmsg show beginner_tutorials/Num
step6:如何调用
python 方式实现
在src/beginner_tutorials/ 下创建talker.py
import rospy
from beginner_tutorials.msg import Num
def talker():
pub = rospy.Publisher('counter', Num, queue_size=10)
rospy.init_node('publisher', anonymous=True)
rate = rospy.Rate(2) # 10hz
cnt = 1000
while not rospy.is_shutdown():
hello_str = "hello world %s" % cnt
rospy.loginfo(hello_str)
pub.publish(cnt)
cnt += 100
rate.sleep()
在bin/Num_publisher 创建Num_publisher
#! /usr/bin/env python
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
python 代码在调用的时候很容易出现找不到module的情况,所以需要合理的管理python的文件
按照ros推荐的风格进行程序规划:
资料来源于:http://wiki.ros.org/rospy_tutorials/Tutorials/Makefile
http://wiki.ros.org/PyStyleGuide Step6.1: 管理好目录
1.no msgs/srvs
packagename
|- src/
|- packagename.py
|- scripts/
|- non-exported python files
2.with msg/srvs
packagename
|- src/
|- packagename/
|- init.py
|- talker.py
|- scripts/
|- non-exported python files
|- bin/Num_publisher
|- setup.py
Step6.2:添加__init__.py文件
Files named init.py are used to mark directories on disk as a Python package
通俗的讲就是作为python 文件夹的标示,没有什么其他作用,所以一般也不添加代码
Step6.3:添加setup.py
## ! DO NOT MANUALLY INVOKE THIS setup.py, USE CATKIN INSTEAD
from distutils.core import setup
from catkin_pkg.python_setup import generate_distutils_setup
# fetch values from package.xml
setup_args = generate_distutils_setup(
packages=['tutorial_package'],
package_dir={'': 'src'},
)
setup(**setup_args)
Step6.4 修改ros python makefile
#package.xml
<buildtool_depend>catkin</buildtool_depend> #限定编译的工具 如果使用ros_build 应该怎么做?
#cmakeList.txt
catkin_python_setup()
还可以指定安装位置,这个我们后续再进行更新
因为我们使用的是python所以在cmakeList.txt中并不需要修改太多内容
cpp 方式实现
#include "ros/ros.h"
#include "beginner_tutorials/Num.h"
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker");
ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<beginner_tutorials::Num>("counter", 1000);
ros::Rate loop_rate(2);
int count = 0;
while (ros::ok())
{
beginner_tutorials::Num msg;
msg.num = count;
chatter_pub.publish(msg);
count++;
//ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
根据代码关键在于根据Num.msg 生成相应的Num.h
资料来源于:
在cmakelist.txt中添加libraries
catkin_package(
# INCLUDE_DIRS include
LIBRARIES beginner_tutorials #因为我们的代码msg和运行代码在一个package中,这个可以注释
CATKIN_DEPENDS roscpp message_runtime
)
include_directories(
include #因为要添加Num.h,这个必须要添加
${catkin_INCLUDE_DIRS}
)
其他库调用我们创建的msg
cd catkin_ws/src
catkin_create_pkg test roscpp rospy std_msgs
修改库依赖
#package.xml
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>rospy</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>beginner_tutorials</build_depend>
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend>
<build_export_depend>std_msgs</build_export_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
修改cmakeList.txt中的依赖选项
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
beginner_tutorials #只要能find 对应的package 就没有什么问题
)
代码部分cpp和python的完全一样
总结
package.xml文件应该怎么写
编译和运行需要的外部库文件需要在package.xml中声明;
如果需要生成message则需要message_generation 这个外部库
如果需要调用外部的message 库函数,调用<build_depend>beginner_tutorials</build_depend>
如果要使用setup.py管理python文件,说明使用的是catkin <buildtool_depend>catkin</buildtool_depend>
cmakelist.txt文件应该怎么写
如果只是生成节点,采用find_package 找到所需的依赖即可
如果需要生成message,1.add_msg;2.generate_msg;3.catkin_package 声明库所需要运行时的工具message_runtime
(ROS独有的找外部包依赖的方法)
如果需要写python的makefile文件,需要使用catkin_python_setup()
如果需要一些头文件,使用include_directories,或者是catkin_package中的LIBRARIES
python 代码如何管理
采用__init__.py 及同一层级的代码是函数,运行代码放置在bin/, 环境代码放置在package/