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
      

      还是挺复杂的。

  • 相关阅读:
    015.Python基础--模块
    014.Python基础--格式化输入输出
    013.Python基础--异常/错误处理
    012.Python基础--装饰器深入
    011.Python基础--装饰器
    010.Python基础--生成器
    汇编的角度分析指针-03(字符串深入理解)
    汇编的角度分析C语言的指针-02
    汇编的角度分析C语言的switch语句
    分析C语言的字节对齐
  • 原文地址:https://www.cnblogs.com/spyplus/p/11544359.html
Copyright © 2011-2022 走看看