使用 catkin 的方式创建自定义的 ros 消息

1 写在前面

  • 消息文件是描述ROS消息字段的简单文本文件,其后缀为.msg,用于生成不同语言的消息源代码。
  • 消息文件放在在 ros pkg 中的/msg文件夹中。
  • 消息只是简单的文本文件,每行具有字段类型和字段名称。

消息文件的格式为:

<字段类型> <字段名称>

注意:<字段类型> 与 <字段名称>直接需使用空格而不能使用Tab

可用的字段类型有:

int8, int16, int32, int64 (plus uint*)
float32, float64
string
time, duration

消息文件支持嵌套,也就是说字段类型可以是其他消息的名称。
另外,字段类型还支持可变长短数组和固定长度数组:

array[]  array[constant] # 使用时直接将 array 替换成类型名

除此之外,在 ROS 中也有一个特殊类型: HeaderHeader 包含常用于 ROS 的时间戳和坐标帧信息。经常会在 msg 文件的第一行放置 Header 头。如在CARLA中的IMU消息的头所包含的信息:

header: 
  seq: 140
  stamp: 
    secs: 96
    nsecs: 355454117
  frame_id: "ego_vehicle/imu/imu1" 

下面是一个消息的示例:

Header header
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/TwistWithCovariance twist

2 创建自定义消息

2.1 创建 ros 包

你也可以在已有的ros pkg 中添加自定义的消息文件,我这里为了演示方便新建了一个 rospkg:

cd ~/catkin_ws/src #转到你的工作空间
catkin_create_pkg my_msg roscpp rospy std_msgs message_generation message_runtime

my_msg是这个 rospkg 的名称;
roscpp rospy std_msgs message_generation message_runtime 依赖项,在构建时,我们需要message_generation,而在运行时,我们只需要message_runtime
如果这一步操作成果会得到类似下文的输出:

Created file my_msg/package.xml
Created file my_msg/CMakeLists.txt
Created folder my_msg/include/my_msg
Created folder my_msg/src
Successfully created files in /home/jk/catkin_ws/my_msg. Please adjust the values in package.xml.

2.2 创建 msg 文件

/my_msg中新建/msg文件夹,在该路径下新建你的消息文件,如我创建Num.msg文件(一般来说消息名的首字母大写),编辑其内容如下并保存。

string first_name
string last_name
uint8 age
uint32 score

2.3 修改 package.xml 文件

打开package.xml 文件, 确保有下面两个语句,且没有被注释

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

由于我们在创建 catkin Package 的时候就声明了对message_generation message_runtim的依赖,所以我们的 package.xml 应该已经有未注释的上面两条语句。
在这里插入图片描述

2.4 修改 CMakeLists.txt 文件

打开包中的 CMakeLists.txt 文件。
确保find_package中以下字段存在且未被注释:

## 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
  message_generation
  roscpp
  rospy
  std_msgs
)

由于我们在创建 catkin Package 的时候就声明了对roscpp rospy std_msgs message_generation message_runtim的依赖,所以我们的 CMakeLists.txt 应该已经有未注释的上面几条语句。我们可能需要删除多余的一项:message_runtime

确保导出消息运行时的依赖项,需要确保下面的语句中CATKIN_DEPENDS message_runtime未被注释。

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES my_msg
CATKIN_DEPENDS message_runtime
#  DEPENDS system_lib
)

然后找到下面的模块:

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

取消注释,并把msg 的文件名替换成你自己的:

add_message_files(
  FILES
  Num.msg
)

我们还要确保generate_messages()模块未被注释:

如果消息中有用到geometry_msgs类型的字段,要把geometry_msgs也添加到下面的模块中去

# Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  std_msgs
)

3 生成 msg 代码文件

退回到上一级目录,使用catkin_make 进行编译:

cd ..
catkin_make

不出意外我们应该已经成功生成了消息文件的c++格式的头文件(如果报错,仔细阅读错误说明应该很容易解决)。
生成的文件在<path to workspace>/devel/include/my_msg,命名和.msg文件一致,为Num.h,内容如下:

// Generated by gencpp from file my_msg/Num.msg
// DO NOT EDIT!


#ifndef MY_MSG_MESSAGE_NUM_H
#define MY_MSG_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 my_msg
{
template <class ContainerAllocator>
struct Num_
{
  typedef Num_<ContainerAllocator> Type;

  Num_()
    : first_name()
    , last_name()
    , age(0)
    , score(0)  {
    }
  Num_(const ContainerAllocator& _alloc)
    : first_name(_alloc)
    , last_name(_alloc)
    , age(0)
    , score(0)  {
  (void)_alloc;
    }



   typedef std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other >  _first_name_type;
  _first_name_type first_name;

   typedef std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other >  _last_name_type;
  _last_name_type last_name;

   typedef uint8_t _age_type;
  _age_type age;

   typedef uint32_t _score_type;
  _score_type score;





  typedef boost::shared_ptr< ::my_msg::Num_<ContainerAllocator> > Ptr;
  typedef boost::shared_ptr< ::my_msg::Num_<ContainerAllocator> const> ConstPtr;

}; // struct Num_

typedef ::my_msg::Num_<std::allocator<void> > Num;

typedef boost::shared_ptr< ::my_msg::Num > NumPtr;
typedef boost::shared_ptr< ::my_msg::Num const> NumConstPtr;

// constants requiring out of line definition



template<typename ContainerAllocator>
std::ostream& operator<<(std::ostream& s, const ::my_msg::Num_<ContainerAllocator> & v)
{
ros::message_operations::Printer< ::my_msg::Num_<ContainerAllocator> >::stream(s, "", v);
return s;
}

} // namespace my_msg

namespace ros
{
namespace message_traits
{



// BOOLTRAITS {'IsFixedSize': False, 'HasHeader': False, 'IsMessage': True}
// {'std_msgs': ['/opt/ros/kinetic/share/std_msgs/cmake/../msg'], 'my_msg': ['/home/jk/catkin_ws/src/my_msg/msg']}

// !!!!!!!!!!! ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__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< ::my_msg::Num_<ContainerAllocator> >
  : FalseType
  { };

template <class ContainerAllocator>
struct IsFixedSize< ::my_msg::Num_<ContainerAllocator> const>
  : FalseType
  { };

template <class ContainerAllocator>
struct HasHeader< ::my_msg::Num_<ContainerAllocator> >
  : FalseType
  { };

template <class ContainerAllocator>
struct HasHeader< ::my_msg::Num_<ContainerAllocator> const>
  : FalseType
  { };

template <class ContainerAllocator>
struct IsMessage< ::my_msg::Num_<ContainerAllocator> >
  : TrueType
  { };

template <class ContainerAllocator>
struct IsMessage< ::my_msg::Num_<ContainerAllocator> const>
  : TrueType
  { };


template<class ContainerAllocator>
struct MD5Sum< ::my_msg::Num_<ContainerAllocator> >
{
  static const char* value()
  {
    return "f8bfa80ae3c7a93455596d9622ad33a9";
  }

  static const char* value(const ::my_msg::Num_<ContainerAllocator>&) { return value(); }
  static const uint64_t static_value1 = 0xf8bfa80ae3c7a934ULL;
  static const uint64_t static_value2 = 0x55596d9622ad33a9ULL;
};

template<class ContainerAllocator>
struct DataType< ::my_msg::Num_<ContainerAllocator> >
{
  static const char* value()
  {
    return "my_msg/Num";
  }

  static const char* value(const ::my_msg::Num_<ContainerAllocator>&) { return value(); }
};

template<class ContainerAllocator>
struct Definition< ::my_msg::Num_<ContainerAllocator> >
{
  static const char* value()
  {
    return "string first_name\n\
string last_name\n\
uint8 age\n\
uint32 score\n\
";
  }

  static const char* value(const ::my_msg::Num_<ContainerAllocator>&) { return value(); }
};

} // namespace message_traits
} // namespace ros

namespace ros
{
namespace serialization
{

  template<class ContainerAllocator> struct Serializer< ::my_msg::Num_<ContainerAllocator> >
  {
    template<typename Stream, typename T> inline static void allInOne(Stream& stream, T m)
    {
      stream.next(m.first_name);
      stream.next(m.last_name);
      stream.next(m.age);
      stream.next(m.score);
    }

    ROS_DECLARE_ALLINONE_SERIALIZER
  }; // struct Num_

} // namespace serialization
} // namespace ros

namespace ros
{
namespace message_operations
{

template<class ContainerAllocator>
struct Printer< ::my_msg::Num_<ContainerAllocator> >
{
  template<typename Stream> static void stream(Stream& s, const std::string& indent, const ::my_msg::Num_<ContainerAllocator>& v)
  {
    s << indent << "first_name: ";
    Printer<std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other > >::stream(s, indent + "  ", v.first_name);
    s << indent << "last_name: ";
    Printer<std::basic_string<char, std::char_traits<char>, typename ContainerAllocator::template rebind<char>::other > >::stream(s, indent + "  ", v.last_name);
    s << indent << "age: ";
    Printer<uint8_t>::stream(s, indent + "  ", v.age);
    s << indent << "score: ";
    Printer<uint32_t>::stream(s, indent + "  ", v.score);
  }
};

} // namespace message_operations
} // namespace ros

#endif // MY_MSG_MESSAGE_NUM_H
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值