zoukankan      html  css  js  c++  java
  • 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
      
      ";
        }
      
        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
      

      还是挺复杂的。

  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    How to check if one path is a child of another path?
    Why there is two completely different version of Reverse for List and IEnumerable?
    在Jenkins中集成Sonarqube
    如何查看sonarqube的版本 how to check the version of sonarqube
    Queue
    BFS广度优先 vs DFS深度优先 for Binary Tree
    Depth-first search and Breadth-first search 深度优先搜索和广度优先搜索
    102. Binary Tree Level Order Traversal 广度优先遍历
    How do I check if a type is a subtype OR the type of an object?
  • 原文地址:https://www.cnblogs.com/spyplus/p/11544359.html
Copyright © 2011-2022 走看看