该节内容主要来自于官方文档的两个小节:
1.使用rosed来编辑
2.创建ros消息的服务
先来看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‘
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是响应。
$ 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 )
$ rosmsg show [message type]
例如,对于上述定义的信息,用如下命令:
$ rosmsg show beginner_tutorials/Num
可以看到返回为:
int64 num
也可以不写全路径,如果你不记得该消息在哪个包下面,可以这样写:
$ rosmsg show Num
返回为:
[beginner_tutorials/Num]: int64 num
$ 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 )
$ 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
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
还是挺复杂的。
原文:https://www.cnblogs.com/spyplus/p/11544359.html