ROS學習筆記9-創建ros消息和服務


該節內容主要來自於官方文檔的兩個小節:
1.使用rosed來編輯
2.創建ros消息的服務

先來看rosed:

  1. rosed
    rosed命令是rosbash的一部分,使用rosed可以直接編輯包中的一個文件,而無需鍵入文件所在的全路徑,用法如下:
    $ rosed [package_name] [filename]
    

    例如我們想編輯roscpp包下的Logger.msg,則輸入如下命令:

    $ rosed roscpp Logger.msg
    

     則會使用vim打開Logger.msg進入編輯狀態。
    同時,rosed支持使用tab鍵實現自動完成功能,用法如下:

    $ rosed [package_name] <tab><tab>
    

    例如:

    $ rosed roscpp <tab><tab>
    

    注意:兩個tab和包名之間有空格。
    會列出roscpp包中的所有的文件:

    Empty.srv                   roscpp.cmake
    genmsg_cpp.py               roscppConfig.cmake
    gensrv_cpp.py               roscppConfig-version.cmake
    GetLoggers.srv              roscpp-msg-extras.cmake
    Logger.msg                  roscpp-msg-paths.cmake
    msg_gen.py                  SetLoggerLevel.srv
    package.xml                 
    

     並且,rosed還可以指定編輯器,默認的采用vim編輯器,可以通過設置~/.bashrc文件中的環境變量來指定編輯器:
    例如輸入如下命令將編輯器設置為nano編輯器。

    export EDITOR='nano -w'
    

     也可以使用如下命令設置為gedit:

    export EDITOR='gedit -w'
    
  2. msg和srv文件介紹
    • msg:msg文件是ros中描述msg消息成員的文本文件,他可以生成不同語言中的消息代碼。
    • srv:srv文件是ros中描述服務類型成員的文本文件,他包含請求和響應兩部分。
    msg文件每行包含一個類型和一個變量名:
    其中,變量類型可以為如下類型:
    • int8, int16, int32, int64 (以及uint)
    • float32, float64
    • string
    • time, duration
    • 其他消息類型
    • 變長度以及定長度的數組[]
    此外還有一個特殊類型,頭類型(Header),Header類型包含一個時間戳和坐標軸信息,這些信息在ROS中很常用。一個典型的ros消息定義如下:
     Header header
      string child_frame_id
      geometry_msgs/PoseWithCovariance pose
      geometry_msgs/TwistWithCovariance twist
    

    srv文件定義與msg類似,也是由不同行組成,每行包含一個變量類型和一個變量名,不過srv包含請求(request)和響應(response)兩個部分,該兩部分用一行三短杠---分隔開。例如:

    int64 A
    int64 B
    ---
    int64 Sum
    

    在上面的例子中:A和B是請求,Sum是響應。

  3. 使用msg
    1. 創建msg
      比如使用如下命令可以在之前的示例包里創建一個新msg:
      $ roscd beginner_tutorials
      $ mkdir msg
      $ echo "int64 num" > msg/Num.msg
      

      該msg只有一行,當然也可以創建一個更復雜的msg

      string first_name
      string last_name
      uint8 age
      uint32 score
      

       然后,為了確保該msg文件能被轉化為其他語言的代碼,需要檢查package.xml中如下兩行存在且未被注釋掉:(查看之后發現默認是注釋掉的)

      <build_depend>message_generation</build_depend>
        <exec_depend>message_runtime</exec_depend>
      

      在編譯期間,我們需要啟用message_generation,在運行期間,我們需要啟用message_runtime。
      然后使用你最喜愛的編輯器打開CMakeLists.txt(可以使用rosed)
      然后在find_package中添加message_generation的條目:

      ## Find catkin macros and libraries
      ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
      ## is used, also find other catkin packages
      find_package(catkin REQUIRED COMPONENTS
        roscpp
        rospy
        std_msgs
        message_generation
      )
      

       同時,確保在運行時依賴中也添加了該消息的依賴:

      catkin_package(
      #  INCLUDE_DIRS include
      #  LIBRARIES begginner_tutorials
      #  CATKIN_DEPENDS roscpp rospy std_msgs
      #  DEPENDS system_lib
      CATKIN_DEPENS message_runtime
      )
      

      找到添加消息文件的代碼段:

      # add_message_files(
      #   FILES
      #   Message1.msg
      #   Message2.msg
      # )
      

       取消注釋並添加該消息文件名:

      add_message_files(
        FILES
        Num.msg
      )
      

      確保generate_message被調用:

      generate_messages(
        DEPENDENCIES
        std_msgs
      )
      
    2. 查看msg的信息
      定義信息之后,可以用rosmsg命令來查看消息的信息:
      $ rosmsg show [message type]
      

      例如,對於上述定義的信息,用如下命令:

      $ rosmsg show beginner_tutorials/Num
      

      可以看到返回為:

      int64 num
      

       也可以不寫全路徑,如果你不記得該消息在哪個包下面,可以這樣寫:

      $ rosmsg show Num
      

       返回為:

      [beginner_tutorials/Num]:
      int64 num
      
  4. 使用srv
    1.  創建srv
      類似於msg,我們先創建一個srv的文件夾:
      $ roscd beginner_tutorials
      $ mkdir srv
      

      可以在其中手動寫一個srv文件,也可以將其他地方的srv文件復制過來,在此處介紹一個ros下面復制文件的命令,roscp,該命令用法如下:

      $ roscp [package_name] [file_to_copy_path] [copy_path]
      

      然后我們將rospy_tutorials包中的srv文件復制過來:

      $ roscp rospy_tutorials AddTwoInts.srv srv/AddTwoInts.srv
      

       同時在package.xml中啟用message_generation和message_runtime(該步與msg相同)。

      然后在find_package的調用中增加message_generation(與msg中相同)。
      不同的是在add_service_files的調用中要添加與服務對應的條目。

      add_service_files(
        FILES
        AddTwoInts.srv
      )
      
    2. 查看srv的信息
      與rosmsg類似,ros也提供了rossrv來查看srv服務相關的信息:
      例如:
      $ rossrv show beginner_tutorials/AddTwoInts
      

      返回:

      int64 a
      int64 b
      ---
      int64 sum
      

      也可以不加路徑:

      $ rossrv show AddTwoInts
      [beginner_tutorials/AddTwoInts]:
      int64 a
      int64 b
      ---
      int64 sum
      
      [rospy_tutorials/AddTwoInts]:
      int64 a
      int64 b
      ---
      int64 sum
  5. 通用步驟(個人感覺應該該節改名為編譯步驟)
    如果進行完了如上步驟,然后就可以編譯這些msg和srv,取消CMakeLists.txt中以下幾行的注釋:
    generate_messages(
      DEPENDENCIES
      std_msgs
    )
    

    然后運行catkin_make進行編譯:

    # In your catkin workspace
    $ roscd beginner_tutorials
    $ cd ../..
    $ catkin_make install
    $ cd -
    

     則會將msg和srv文件編譯成其他語言的代碼。例如,對於msg,C++的頭文件會包含在~/catkin_ws/devel/include/beginner_tutorials/中;
    python的源文件會包含在~/catkin_ws/devel/lib/python2.7/dist-packages/beginner_tutorials/msg中;
    ~/catkin_ws/devel/share/common-lisp/ros/beginner_tutorials/msg/中。
    srv文件對於C++會和msg文件生成的源文件在統一文件夾中,而python和lisp的srv文件生成的文件會在單獨的srv文件夾中,該文件夾與msg文件夾在同一個目錄下。
    看一個C++的msg頭文件:

    // Generated by gencpp from file begginner_tutorials/Num.msg
    // DO NOT EDIT!
    
    
    #ifndef BEGGINNER_TUTORIALS_MESSAGE_NUM_H
    #define BEGGINNER_TUTORIALS_MESSAGE_NUM_H
    
    
    #include <string>
    #include <vector>
    #include <map>
    
    #include <ros/types.h>
    #include <ros/serialization.h>
    #include <ros/builtin_message_traits.h>
    #include <ros/message_operations.h>
    
    
    namespace begginner_tutorials
    {
    template <class ContainerAllocator>
    struct Num_
    {
      typedef Num_<ContainerAllocator> Type;
    
      Num_()
        : num(0)  {
        }
      Num_(const ContainerAllocator& _alloc)
        : num(0)  {
      (void)_alloc;
        }
    
    
    
       typedef int64_t _num_type;
      _num_type num;
    
    
    
    
    
      typedef boost::shared_ptr< ::begginner_tutorials::Num_<ContainerAllocator> > Ptr;
      typedef boost::shared_ptr< ::begginner_tutorials::Num_<ContainerAllocator> const> ConstPtr;
    
    }; // struct Num_
    
    typedef ::begginner_tutorials::Num_<std::allocator<void> > Num;
    
    typedef boost::shared_ptr< ::begginner_tutorials::Num > NumPtr;
    typedef boost::shared_ptr< ::begginner_tutorials::Num const> NumConstPtr;
    
    // constants requiring out of line definition
    
    
    
    template<typename ContainerAllocator>
    std::ostream& operator<<(std::ostream& s, const ::begginner_tutorials::Num_<ContainerAllocator> & v)
    {
    ros::message_operations::Printer< ::begginner_tutorials::Num_<ContainerAllocator> >::stream(s, "", v);
    return s;
    }
    
    } // namespace begginner_tutorials
    
    namespace ros
    {
    namespace message_traits
    {
    
    
    
    // BOOLTRAITS {'IsFixedSize': True, 'IsMessage': True, 'HasHeader': False}
    // {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'begginner_tutorials': ['/home/shao/catkin_ws/src/begginner_tutorials/msg']}
    
    // !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_parsed_fields', 'constants', 'fields', 'full_name', 'has_header', 'header_present', 'names', 'package', 'parsed_fields', 'short_name', 'text', 'types']
    
    
    
    
    template <class ContainerAllocator>
    struct IsFixedSize< ::begginner_tutorials::Num_<ContainerAllocator> >
      : TrueType
      { };
    
    template <class ContainerAllocator>
    struct IsFixedSize< ::begginner_tutorials::Num_<ContainerAllocator> const>
      : TrueType
      { };
    
    template <class ContainerAllocator>
    struct IsMessage< ::begginner_tutorials::Num_<ContainerAllocator> >
      : TrueType
      { };
    
    template <class ContainerAllocator>
    struct IsMessage< ::begginner_tutorials::Num_<ContainerAllocator> const>
      : TrueType
      { };
    
    template <class ContainerAllocator>
    struct HasHeader< ::begginner_tutorials::Num_<ContainerAllocator> >
      : FalseType
      { };
    
    template <class ContainerAllocator>
    struct HasHeader< ::begginner_tutorials::Num_<ContainerAllocator> const>
      : FalseType
      { };
    
    
    template<class ContainerAllocator>
    struct MD5Sum< ::begginner_tutorials::Num_<ContainerAllocator> >
    {
      static const char* value()
      {
        return "57d3c40ec3ac3754af76a83e6e73127a";
      }
    
      static const char* value(const ::begginner_tutorials::Num_<ContainerAllocator>&) { return value(); }
      static const uint64_t static_value1 = 0x57d3c40ec3ac3754ULL;
      static const uint64_t static_value2 = 0xaf76a83e6e73127aULL;
    };
    
    template<class ContainerAllocator>
    struct DataType< ::begginner_tutorials::Num_<ContainerAllocator> >
    {
      static const char* value()
      {
        return "begginner_tutorials/Num";
      }
    
      static const char* value(const ::begginner_tutorials::Num_<ContainerAllocator>&) { return value(); }
    };
    
    template<class ContainerAllocator>
    struct Definition< ::begginner_tutorials::Num_<ContainerAllocator> >
    {
      static const char* value()
      {
        return "int64 num\n\
    ";
      }
    
      static const char* value(const ::begginner_tutorials::Num_<ContainerAllocator>&) { return value(); }
    };
    
    } // namespace message_traits
    } // namespace ros
    
    namespace ros
    {
    namespace serialization
    {
    
      template<class ContainerAllocator> struct Serializer< ::begginner_tutorials::Num_<ContainerAllocator> >
      {
        template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)
        {
          stream.next(m.num);
        }
    
        ROS_DECLARE_ALLINONE_SERIALIZER
      }; // struct Num_
    
    } // namespace serialization
    } // namespace ros
    
    namespace ros
    {
    namespace message_operations
    {
    
    template<class ContainerAllocator>
    struct Printer< ::begginner_tutorials::Num_<ContainerAllocator> >
    {
      template<typename Stream> static void stream(Stream& s, const std::string& indent, const ::begginner_tutorials::Num_<ContainerAllocator>& v)
      {
        s << indent << "num: ";
        Printer<int64_t>::stream(s, indent + "  ", v.num);
      }
    };
    
    } // namespace message_operations
    } // namespace ros
    
    #endif // BEGGINNER_TUTORIALS_MESSAGE_NUM_H
    

    還是挺復雜的。


免責聲明!

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



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