Ros學習——C++發布器publisher和訂閱器subscriber


 

1.編寫發布器

  • 初始化 ROS 系統
  • 在 ROS 網絡內廣播我們將要在 chatter 話題上發布 std_msgs/String 類型的消息

  • 以每秒 10 次的頻率在 chatter 上發布消息

在 beginner_tutorials package 里創建 src/talker.cpp 文件:

#include "ros/ros.h"      //一個實用的頭文件,它引用了 ROS 系統中大部分常用的頭文件
#include "std_msgs/String.h"  //引用了 std_msgs/String 消息, 它存放在 std_msgs package 里,是由 String.msg 文件自動生成的頭文件。

#include <sstream>

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
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");  //初始化 ROS.可指定節點的名稱。節點的名稱必須唯一(名稱內不能包含 / 等符號)

  /**
   * 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;  //為這個進程的節點創建一個句柄。
              //第一個創建的 NodeHandle 會為節點進行初始化,最后一個銷毀的 NodeHandle 則會釋放該節點所占用的所有資源
  /**
   * 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);//告訴master 我們將要在 chatter(話題名) 上發布 std_msgs/String 消息類型的消息。
             //如果我們發布的消息的頻率太高,緩沖區中的消息在大於 1000 個的時候就會開始丟棄先前發布的消息。
             //
advertise返回一個 ros::Publisher 對象,它有兩個作用: 1) 它有一個 publish() 成員函數可以讓你在topic上發布消息; 2) 如果消息類型不對,它會拒絕發布。

  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())      //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());//ROS_INFO 和其他類似的函數可以用來代替 printf/cout 等函數。

    /**
     * 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);//向所有訂閱 chatter 話題的節點發送消息。

    ros::spinOnce();      //ros::spinOnce()這一語句,否則你的回調函數就永遠也不會被調用

    loop_rate.sleep();    //調用 ros::Rate 對象來休眠一段時間以使得發布頻率為 10Hz。
    ++count;
  }


  return 0;
}

 

2.編寫訂閱器

  

  • 初始化ROS系統
  • 訂閱 chatter 話題

  • 進入自循環,等待消息的到達
  • 當消息到達,調用 chatterCallback() 函數

 

在 beginner_tutorials package 目錄下創建 src/listener.cpp 文件:

#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)//是一個回調函數,當接收到 chatter 話題的時候就會被調用。
{
  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);

//告訴 master 我們要訂閱 chatter 話題上的消息。當有消息發布到這個話題時,ROS 就會調用 chatterCallback() 函數。第二個參數是隊列大小,以防我們處理消息的速度不夠快,當緩存達到 1000 條消息后,再有新的消息到來就將開始丟棄先前接收的消息。
 
         

 

/** * 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();//ros::spin() 進入自循環,可以盡可能快的調用消息回調函數。

return 0;
}

 

3.編譯

cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)

## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv)

## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)

## Declare a catkin package
catkin_package(
 
         

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)

  • 1-2會生成兩個可執行文件, talker 和 listener, 默認存儲到 devel space 目錄下,具體在~/catkin_ws/devel/lib/<package name> 中.
  • 3.如果在 *Groovy* 版本下,你可以使用下邊的這個變量來添加對所有必須的文件依賴:
add_dependencies(talker ${catkin_EXPORTED_TARGETS})
  • 4.運行 catkin_make

 4.測試結果:

 

 

5.問題:

1.當你在package.xml中,添加完run_depend后,編譯出錯,顯示The manifest must not cotain the following  tags:run_depend。

原因:軟件包格式分兩種,第一種的四種依賴關系分別是:

<buildtool_depend>

<build_depend>

<run_depend>

<test_depend>

第二種的依賴關系變成:

<buildtool_depend>

<build_depend>

<build_export_depend>

<exec_depend>

<test_depend>

<doc_depend>

 

解決:當你run_depend出錯時,有可能是你的軟件包格式是第二種,所以要把run_depend改成exec_depend

 

2.invoking "make cmake_check_build_system" failed

仔細檢查:

cmake_minimum_required(VERSION 2.8.3)
project(beginner_tutorials)

## Find catkin and any catkin packages
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)

## Declare ROS messages and services
add_message_files(DIRECTORY msg FILES Num.msg)
add_service_files(DIRECTORY srv FILES AddTwoInts.srv)

## Generate added messages and services
generate_messages(DEPENDENCIES std_msgs)

## Declare a catkin package
catkin_package()  #尤其要注意,里面為空否則報上面的錯

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM