3.1.2 话题与服务相关对象
C++
在 roscpp 中,话题和服务的相关对象一般由 NodeHandle 创建。
NodeHandle有一个重要作用是可以用于设置命名空间,这是后期的重点,但是本章暂不介绍。
1.发布对象
对象获取:
/**
* \brief 根据话题生成发布对象
*
* 在 ROS master 注册并返回一个发布者对象,该对象可以发布消息
*
* 使用示例如下:
*
* ros::Publisher pub = handle.advertise<std_msgs::Empty>("my_topic", 1);
*
* \param topic 发布消息使用的话题
*
* \param queue_size 等待发送给订阅者的最大消息数量
*
* \param latch (optional) 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
*
* \return 调用成功时,会返回一个发布对象
*
*
*/
template <class M>
Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)
消息发布函数:
/**
* 发布消息
*/
template <typename M>
void publish(const M& message) const
2.订阅对象
对象获取:
/**
* \brief 生成某个话题的订阅对象
*
* 该函数将根据给定的话题在ROS master 注册,并自动连接相同主题的发布方,每接收到一条消息,都会调用回调
* 函数,并且传入该消息的共享指针,该消息不能被修改,因为可能其他订阅对象也会使用该消息。
*
* 使用示例如下:
void callback(const std_msgs::Empty::ConstPtr& message)
{
}
ros::Subscriber sub = handle.subscribe("my_topic", 1, callback);
*
* \param M [template] M 是指消息类型
* \param topic 订阅的话题
* \param queue_size 消息队列长度,超出长度时,头部的消息将被弃用
* \param fp 当订阅到一条消息时,需要执行的回调函数
* \return 调用成功时,返回一个订阅者对象,失败时,返回空对象
*
void callback(const std_msgs::Empty::ConstPtr& message){...}
ros::NodeHandle nodeHandle;
ros::Subscriber sub = nodeHandle.subscribe("my_topic", 1, callback);
if (sub) // Enter if subscriber is valid
{
...
}
*/
template<class M>
Subscriber subscribe(const std::string& topic, uint32_t queue_size, void(*fp)(const boost::shared_ptr<M const>&), const TransportHints& transport_hints = TransportHints())
3.服务对象
对象获取:
/**
* \brief 生成服务端对象
*
* 该函数可以连接到 ROS master,并提供一个具有给定名称的服务对象。
*
* 使用示例如下:
\verbatim
bool callback(std_srvs::Empty& request, std_srvs::Empty& response)
{
return true;
}
ros::ServiceServer service = handle.advertiseService("my_service", callback);
\endverbatim
*
* \param service 服务的主题名称
* \param srv_func 接收到请求时,需要处理请求的回调函数
* \return 请求成功时返回服务对象,否则返回空对象:
\verbatim
bool Foo::callback(std_srvs::Empty& request, std_srvs::Empty& response)
{
return true;
}
ros::NodeHandle nodeHandle;
Foo foo_object;
ros::ServiceServer service = nodeHandle.advertiseService("my_service", callback);
if (service) // Enter if advertised service is valid
{
...
}
\endverbatim
*/
template<class MReq, class MRes>
ServiceServer advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&))
4.客户端对象
对象获取:
/**
* @brief 创建一个服务客户端对象
*
* 当清除最后一个连接的引用句柄时,连接将被关闭。
*
* @param service_name 服务主题名称
*/
template<class Service>
ServiceClient serviceClient(const std::string& service_name, bool persistent = false,
const M_string& header_values = M_string())
请求发送函数:
/**
* @brief 发送请求
* 返回值为 bool 类型,true,请求处理成功,false,处理失败。
*/
template<class Service>
bool call(Service& service)
等待服务函数1:
/**
* ros::service::waitForService("addInts");
* \brief 等待服务可用,否则一致处于阻塞状态
* \param service_name 被"等待"的服务的话题名称
* \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭
* \return 成功返回 true,否则返回 false。
*/
ROSCPP_DECL bool waitForService(const std::string& service_name, ros::Duration timeout = ros::Duration(-1));
等待服务函数2:
/**
* client.waitForExistence();
* \brief 等待服务可用,否则一致处于阻塞状态
* \param timeout 等待最大时常,默认为 -1,可以永久等待直至节点关闭
* \return 成功返回 true,否则返回 false。
*/
bool waitForExistence(ros::Duration timeout = ros::Duration(-1));
Python
1.发布对象
对象获取:
class Publisher(Topic):
"""
在ROS master注册为相关话题的发布方
"""
def __init__(self, name, data_class, subscriber_listener=None, tcp_nodelay=False, latch=False, headers=None, queue_size=None):
"""
Constructor
@param name: 话题名称
@type name: str
@param data_class: 消息类型
@param latch: 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
@type latch: bool
@param queue_size: 等待发送给订阅者的最大消息数量
@type queue_size: int
"""
消息发布函数:
def publish(self, *args, **kwds):
"""
发布消息
"""
2.订阅对象
对象获取:
class Subscriber(Topic):
"""
类注册为指定主题的订阅者,其中消息是给定类型的。
"""
def __init__(self, name, data_class, callback=None, callback_args=None,
queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):
"""
Constructor.
@param name: 话题名称
@type name: str
@param data_class: 消息类型
@type data_class: L{Message} class
@param callback: 处理订阅到的消息的回调函数
@type callback: fn(msg, cb_args)
@param queue_size: 消息队列长度,超出长度时,头部的消息将被弃用
"""
3.服务对象
对象获取:
class Service(ServiceImpl):
"""
声明一个ROS服务
使用示例::
s = Service('getmapservice', GetMap, get_map_handler)
"""
def __init__(self, name, service_class, handler,
buff_size=DEFAULT_BUFF_SIZE, error_handler=None):
"""
@param name: 服务主题名称 ``str``
@param service_class:服务消息类型
@param handler: 回调函数,处理请求数据,并返回响应数据
@type handler: fn(req)->resp
"""
4.客户端对象
对象获取:
class ServiceProxy(_Service):
"""
创建一个ROS服务的句柄
示例用法::
add_two_ints = ServiceProxy('add_two_ints', AddTwoInts)
resp = add_two_ints(1, 2)
"""
def __init__(self, name, service_class, persistent=False, headers=None):
"""
ctor.
@param name: 服务主题名称
@type name: str
@param service_class: 服务消息类型
@type service_class: Service class
"""
请求发送函数:
def call(self, *args, **kwds):
"""
发送请求,返回值为响应数据
"""
等待服务函数:
def wait_for_service(service, timeout=None):
"""
调用该函数时,程序会处于阻塞状态直到服务可用
@param service: 被等待的服务话题名称
@type service: str
@param timeout: 超时时间
@type timeout: double|rospy.Duration
"""