来源:http://wiki.ros.org/realtime_tools
在进行机械臂的实时控制时,为了尽可能的保证话题的实时性,我们使用官方的realtime_tools。
下面看看官方说明:
此包包含一组可以在硬实时线程中使用的工具,而不会破坏实时行为。 这些工具目前仅提供
realtime publisher,这使得它可以从实时线程向ROS主题发布消息。
realtime_tools :: RealtimePublisher允许编写C ++实时控制器的用户从硬实时循环中发布ROS主题上的消息。 普通的ROS发布者不是实时可靠的,不应该在实时控制器的更新循环中使用。 RealtimePublisher是ROS发布者的包装器; 包装器创建一个额外的非实时线程,用于发布ROS主题的消息。 下面的示例显示了实时发布者在实时控制器的init()和update()方法中的典型用法:
#include
bool MyController::init(pr2_mechanism_model::RobotState *robot,
ros::NodeHandle &n)
{
...
realtime_pub = new
realtime_tools::RealtimePublisher<mgs_type>(n, "topic", 4);
return true;
}
void MyController::update()
{
if (realtime_pub->trylock()){
realtime_pub->msg_.a_field = "hallo";
realtime_pub->msg_.header.stamp = ros::Time::now();
realtime_pub->unlockAndPublish();
}
...
}
下面看看class RealtimePublisher的定义
/*
* Copyright (c) 2008, Willow Garage, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Willow Garage, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Publishing ROS messages is difficult, as the publish function is
* not realtime safe. This class provides the proper locking so that
* you can call publish in realtime and a separate (non-realtime)
* thread will ensure that the message gets published over ROS.
*
* Author: Stuart Glaser
*/
#ifndef REALTIME_TOOLS__REALTIME_PUBLISHER_H_
#define REALTIME_TOOLS__REALTIME_PUBLISHER_H_
#include
#include
#include
#include
#include
#include
#include
#include
namespace realtime_tools {
template <class Msg>
class RealtimePublisher : boost::noncopyable
{
public:
/// The msg_ variable contains the data that will get published on the ROS topic.
Msg msg_;
/** \brief Constructor for the realtime publisher
*
* \param node the nodehandle that specifies the namespace (or prefix) that is used to advertise the ROS topic
* \param topic the topic name to advertise
* \param queue_size the size of the outgoing ROS buffer
* \param latched . optional argument (defaults to false) to specify is publisher is latched or not
*/
RealtimePublisher(const ros::NodeHandle &node, const std::string &topic, int queue_size, bool latched=false)
: topic_(topic), node_(node), is_running_(false), keep_running_(false), turn_(REALTIME)
{
construct(queue_size, latched);
}
RealtimePublisher()
: is_running_(false), keep_running_(false), turn_(REALTIME)
{
}
/// Destructor
~RealtimePublisher()
{
stop();
while (is_running())
{
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
publisher_.shutdown();
}
void init(const ros::NodeHandle &node, const std::string &topic, int queue_size, bool latched=false)
{
topic_ = topic;
node_ = node;
construct(queue_size, latched);
}
/// Stop the realtime publisher from sending out more ROS messages
void stop()
{
keep_running_ = false;
#ifdef NON_POLLING
updated_cond_.notify_one(); // So the publishing loop can exit
#endif
}
/** \brief Try to get the data lock from realtime
*
* To publish data from the realtime loop, you need to run trylock to
* attempt to get unique access to the msg_ variable. Trylock returns
* true if the lock was aquired, and false if it failed to get the lock.
*/
bool trylock()
{
if (msg_mutex_.try_lock())
{
if (turn_ == REALTIME)
{
return true;
}
else
{
msg_mutex_.unlock();
return false;
}
}
else
{
return false;
}
}
/** \brief Unlock the msg_ variable
*
* After a successful trylock and after the data is written to the mgs_
* variable, the lock has to be released for the message to get
* published on the specified topic.
*/
void unlockAndPublish()
{
turn_ = NON_REALTIME;
msg_mutex_.unlock();
#ifdef NON_POLLING
updated_cond_.notify_one();
#endif
}
/** \brief Get the data lock form non-realtime
*
* To publish data from the realtime loop, you need to run trylock to
* attempt to get unique access to the msg_ variable. Trylock returns
* true if the lock was aquired, and false if it failed to get the lock.
*/
void lock()
{
#ifdef NON_POLLING
msg_mutex_.lock();
#else
// never actually block on the lock
while (!msg_mutex_.try_lock())
{
std::this_thread::sleep_for(std::chrono::microseconds(200));
}
#endif
}
/** \brief Unlocks the data without publishing anything
*
*/
void unlock()
{
msg_mutex_.unlock();
}
private:
void construct(int queue_size, bool latched=false)
{
publisher_ = node_.advertise<Msg>(topic_, queue_size, latched);
keep_running_ = true;
thread_ = boost::thread(&RealtimePublisher::publishingLoop, this);
}
bool is_running() const { return is_running_; }
void publishingLoop()
{
is_running_ = true;
turn_ = REALTIME;
while (keep_running_)
{
Msg outgoing;
// Locks msg_ and copies it
lock();
while (turn_ != NON_REALTIME && keep_running_)
{
#ifdef NON_POLLING
updated_cond_.wait(lock);
#else
unlock();
std::this_thread::sleep_for(std::chrono::microseconds(500));
lock();
#endif
}
outgoing = msg_;
turn_ = REALTIME;
unlock();
// Sends the outgoing message
if (keep_running_)
publisher_.publish(outgoing);
}
is_running_ = false;
}
std::string topic_;
ros::NodeHandle node_;
ros::Publisher publisher_;
volatile bool is_running_;
volatile bool keep_running_;
boost::thread thread_;
boost::mutex msg_mutex_; // Protects msg_
#ifdef NON_POLLING
boost::condition_variable updated_cond_;
#endif
enum {REALTIME, NON_REALTIME};
int turn_; // Who's turn is it to use msg_?
};
#include
template <class Msg>
using RealtimePublisherSharedPtr = std::shared_ptr<RealtimePublisher<Msg> >;
}
#endif