ROS开发日记(3)——分别用C++与Python实现消息的发布与订阅

代码地址:https://github.com/hanjintao1996/ROS-/tree/master

(刚发现linux可以PrtSc键加shift截图) 

首先需要在电脑安装ROS系统,安装完成后可以运行以下指令测试,重点是要打开三个不同的终端。

roscore
rosrun turtlesim turtlesim_node
rosrun turtlesim turtle_teleop_key

如果你的电脑出现了一只可以控制打小乌龟,那证明你的ROS运行正常。

消息的发布与订阅是必須掌握的內容,因此下面简单进行实现。


利用C++:

首先,需要创建工作区,也就是工作目录,打开终端,输入 mkdir rostest,之后输入cd rostest,进入这个工作区。

之后创建 mkdir src。进入你第一步中创建的子目录src中(cd src),然后在这个目录下运行

catkin_create_pkg beginner_tutorials std_msgs rospy roscpp

输入ls,可以看到多了cmake,xml文件与两个文件夹。

在src中,创建两个cpp文件,分别命名为

talker: 

#include "ros/ros.h"
#include "std_msgs/String.h"
 
#include <sstream>
int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line. For programmatic
   * remappings you can use a different version of init() which takes remappings
   * directly, but for most command-line programs, passing argc and argv is the easiest
   * way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "talker");
 
  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;
 
  /**
   * The advertise() function is how you tell ROS that you want to
   * publish on a given topic name. This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing. After this advertise() call is made, the master
   * node will notify anyone who is trying to subscribe to this topic name,
   * and they will in turn negotiate a peer-to-peer connection with this
   * node.  advertise() returns a Publisher object which allows you to
   * publish messages on that topic through a call to publish().  Once
   * all copies of the returned Publisher object are destroyed, the topic
   * will be automatically unadvertised.
   *
   * The second parameter to advertise() is the size of the message queue
   * used for publishing messages.  If messages are published more quickly
   * than we can send them, the number here specifies how many messages to
   * buffer up before throwing some away.
   */
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
 
  ros::Rate loop_rate(10);
 
  /**
   * A count of how many messages we have sent. This is used to create
   * a unique string for each message.
   */
  int count = 0;
  while (ros::ok())
  {
    /**
     * This is a message object. You stuff it with data, and then publish it.
     */
    std_msgs::String msg;
 
    std::stringstream ss;
    ss << "hello world" << count;
    msg.data = ss.str();
 
    ROS_INFO("%s", msg.data.c_str());
 
    /**
     * The publish() function is how you send messages. The parameter
     * is the message object. The type of this object must agree with the type
     * given as a template parameter to the advertise<>() call, as was done
     * in the constructor above.
     */
    chatter_pub.publish(msg);
 
    ros::spinOnce();
 
    loop_rate.sleep();
    count = count*count;
  }
 
 
  return 0;
}

 listener:

#include "ros/ros.h"
#include "std_msgs/String.h"
 
/**
 * This tutorial demonstrates simple receipt of messages over the ROS system.
 */
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}
 
int main(int argc, char **argv)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line. For programmatic
   * remappings you can use a different version of init() which takes remappings
   * directly, but for most command-line programs, passing argc and argv is the easiest
   * way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "listener");
 
  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  ros::NodeHandle n;
 
  /**
   * The subscribe() call is how you tell ROS that you want to receive messages
   * on a given topic.  This invokes a call to the ROS
   * master node, which keeps a registry of who is publishing and who
   * is subscribing.  Messages are passed to a callback function, here
   * called chatterCallback.  subscribe() returns a Subscriber object that you
   * must hold on to until you want to unsubscribe.  When all copies of the Subscriber
   * object go out of scope, this callback will automatically be unsubscribed from
   * this topic.
   *
   * The second parameter to the subscribe() function is the size of the message
   * queue.  If messages are arriving faster than they are being processed, this
   * is the number of messages that will be buffered up before beginning to throw
   * away the oldest ones.
   */
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
 
  /**
   * ros::spin() will enter a loop, pumping callbacks.  With this version, all
   * callbacks will be called from within this thread (the main one).  ros::spin()
   * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
   */
  ros::spin();
 
  return 0;
}

在编译我们创建的节点之前,我们还需要编辑Cmakelist.txt文件(注意:是beginner_tutorials项目包下的CMakelist文件),告诉编辑器我们需要编辑什么文件,需要什么依赖。

输入:$ gedit CMakeLists.txt
在文件末尾添加如下语句:

include_directories(include ${catkin_INCLUDE_DIRS})

add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)

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


之后输入两次 cd ..  返回工作区目录,输入 catkin_make

若出现上图则编译成功, 此时在工作区目录。输入source devel/setup.bash,   在bash中注册,否则会出现找不到包的错误,之后打开新终端,输入roscore启动ROS

刚才输入source devel/setup.bash的终端,输入rosrun beginner_tutorials talker 运行发布者

同理在工作区打开新终端,输入source devel/setup.bash,再输入rosrun beginner_tutorials  listener 运行订阅者,运行截图如下

ctrl+c可以停止进程。

以上便是简单的C++ ROS通信程序。 


Python版本:

在上边的工作目录的src下,输入 catkin_create_pkg  pythontest std_msgs rospy roscpp ,之后进入此目录,在src中新建两个python文件。

talker:

import rospy
from std_msgs.msg import String
 
def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()
 
if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
!

listener:

#!/usr/bin/env python
import rospy
from std_msgs.msg import String
 
def callback(data):
    rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
    
def listener():
 
    rospy.init_node('listener', anonymous=True)
 
    rospy.Subscriber("chatter", String, callback)
 
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()
 
if __name__ == '__main__':
    listener()

python可以省去编译环节。

在终端打开 roscore

之后直接在刚才的src目录打开终端,输入python talker.py,直接运行发布者

同理,新建终端python listener.py,运行订阅者

如上图,python的一个发布-订阅程序已经完成,比C++要简单很多,当然也相应打牺牲了一部分性能。 


以上的程序与步骤参考自:

 Rospy的官方教程代码讲解(一)发布与订阅 https://blog.csdn.net/seeseeatre/article/details/79178408

ROS第一个小程序:https://blog.csdn.net/xiao__run/article/details/84675245

自己动手写一个ROS程序:https://blog.csdn.net/yake827/article/details/44564057

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值