git commit -m "first commit"
This commit is contained in:
201
navigations/geometry2/tf2_ros/src/buffer.cpp
Executable file
201
navigations/geometry2/tf2_ros/src/buffer.cpp
Executable file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** \author Wim Meeussen */
|
||||
|
||||
|
||||
#include "tf2_ros/buffer.h"
|
||||
|
||||
#include <ros/assert.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace tf2_ros
|
||||
{
|
||||
|
||||
static const double CAN_TRANSFORM_POLLING_SCALE = 0.01;
|
||||
|
||||
Buffer::Buffer(ros::Duration cache_time, bool debug) :
|
||||
BufferCore(cache_time)
|
||||
{
|
||||
if(debug && !ros::service::exists("~tf2_frames", false))
|
||||
{
|
||||
ros::NodeHandle n("~");
|
||||
frames_server_ = n.advertiseService("tf2_frames", &Buffer::getFrames, this);
|
||||
}
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped
|
||||
Buffer::lookupTransform(const std::string& target_frame, const std::string& source_frame,
|
||||
const ros::Time& time, const ros::Duration timeout) const
|
||||
{
|
||||
canTransform(target_frame, source_frame, time, timeout);
|
||||
return lookupTransform(target_frame, source_frame, time);
|
||||
}
|
||||
|
||||
|
||||
geometry_msgs::TransformStamped
|
||||
Buffer::lookupTransform(const std::string& target_frame, const ros::Time& target_time,
|
||||
const std::string& source_frame, const ros::Time& source_time,
|
||||
const std::string& fixed_frame, const ros::Duration timeout) const
|
||||
{
|
||||
canTransform(target_frame, target_time, source_frame, source_time, fixed_frame, timeout);
|
||||
return lookupTransform(target_frame, target_time, source_frame, source_time, fixed_frame);
|
||||
}
|
||||
|
||||
/** This is a workaround for the case that we're running inside of
|
||||
rospy and ros::Time is not initialized inside the c++ instance.
|
||||
This makes the system fall back to Wall time if not initialized.
|
||||
*/
|
||||
ros::Time now_fallback_to_wall()
|
||||
{
|
||||
try
|
||||
{
|
||||
return ros::Time::now();
|
||||
}
|
||||
catch (ros::TimeNotInitializedException ex)
|
||||
{
|
||||
ros::WallTime wt = ros::WallTime::now();
|
||||
return ros::Time(wt.sec, wt.nsec);
|
||||
}
|
||||
}
|
||||
|
||||
/** This is a workaround for the case that we're running inside of
|
||||
rospy and ros::Time is not initialized inside the c++ instance.
|
||||
This makes the system fall back to Wall time if not initialized.
|
||||
https://github.com/ros/geometry/issues/30
|
||||
*/
|
||||
void sleep_fallback_to_wall(const ros::Duration& d)
|
||||
{
|
||||
try
|
||||
{
|
||||
d.sleep();
|
||||
}
|
||||
catch (ros::TimeNotInitializedException ex)
|
||||
{
|
||||
ros::WallDuration wd = ros::WallDuration(d.sec, d.nsec);
|
||||
wd.sleep();
|
||||
}
|
||||
}
|
||||
|
||||
void conditionally_append_timeout_info(std::string * errstr, const ros::Time& start_time,
|
||||
const ros::Duration& timeout)
|
||||
{
|
||||
if (errstr)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ". canTransform returned after "<< (now_fallback_to_wall() - start_time).toSec() \
|
||||
<<" timeout was " << timeout.toSec() << ".";
|
||||
(*errstr) += ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Buffer::canTransform(const std::string& target_frame, const std::string& source_frame,
|
||||
const ros::Time& time, const ros::Duration timeout, std::string* errstr) const
|
||||
{
|
||||
// Clear the errstr before populating it if it's valid.
|
||||
if (errstr)
|
||||
{
|
||||
errstr->clear();
|
||||
}
|
||||
|
||||
if (!checkAndErrorDedicatedThreadPresent(errstr))
|
||||
return false;
|
||||
|
||||
// poll for transform if timeout is set
|
||||
ros::Time start_time = now_fallback_to_wall();
|
||||
const ros::Duration sleep_duration = timeout * CAN_TRANSFORM_POLLING_SCALE;
|
||||
while (now_fallback_to_wall() < start_time + timeout &&
|
||||
!canTransform(target_frame, source_frame, time) &&
|
||||
(now_fallback_to_wall()+ros::Duration(3.0) >= start_time) && //don't wait when we detect a bag loop
|
||||
(ros::ok() || !ros::isInitialized())) // Make sure we haven't been stopped (won't work for pytf)
|
||||
{
|
||||
sleep_fallback_to_wall(sleep_duration);
|
||||
}
|
||||
bool retval = canTransform(target_frame, source_frame, time, errstr);
|
||||
conditionally_append_timeout_info(errstr, start_time, timeout);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Buffer::canTransform(const std::string& target_frame, const ros::Time& target_time,
|
||||
const std::string& source_frame, const ros::Time& source_time,
|
||||
const std::string& fixed_frame, const ros::Duration timeout, std::string* errstr) const
|
||||
{
|
||||
// Clear the errstr before populating it if it's valid.
|
||||
if (errstr)
|
||||
{
|
||||
errstr->clear();
|
||||
}
|
||||
|
||||
if (!checkAndErrorDedicatedThreadPresent(errstr))
|
||||
return false;
|
||||
|
||||
// poll for transform if timeout is set
|
||||
ros::Time start_time = now_fallback_to_wall();
|
||||
const ros::Duration sleep_duration = timeout * CAN_TRANSFORM_POLLING_SCALE;
|
||||
while (now_fallback_to_wall() < start_time + timeout &&
|
||||
!canTransform(target_frame, target_time, source_frame, source_time, fixed_frame) &&
|
||||
(now_fallback_to_wall()+ros::Duration(3.0) >= start_time) && //don't wait when we detect a bag loop
|
||||
(ros::ok() || !ros::isInitialized())) // Make sure we haven't been stopped (won't work for pytf)
|
||||
{
|
||||
sleep_fallback_to_wall(sleep_duration);
|
||||
}
|
||||
bool retval = canTransform(target_frame, target_time, source_frame, source_time, fixed_frame, errstr);
|
||||
conditionally_append_timeout_info(errstr, start_time, timeout);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
bool Buffer::getFrames(tf2_msgs::FrameGraph::Request& req, tf2_msgs::FrameGraph::Response& res)
|
||||
{
|
||||
res.frame_yaml = allFramesAsYAML();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Buffer::checkAndErrorDedicatedThreadPresent(std::string* error_str) const
|
||||
{
|
||||
if (isUsingDedicatedThread())
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
if (error_str)
|
||||
*error_str = tf2_ros::threading_error;
|
||||
|
||||
ROS_ERROR("%s", tf2_ros::threading_error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
162
navigations/geometry2/tf2_ros/src/buffer_client.cpp
Executable file
162
navigations/geometry2/tf2_ros/src/buffer_client.cpp
Executable file
@@ -0,0 +1,162 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright (c) 2009, 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 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.
|
||||
*
|
||||
* Author: Eitan Marder-Eppstein
|
||||
*********************************************************************/
|
||||
#include <tf2_ros/buffer_client.h>
|
||||
|
||||
namespace tf2_ros
|
||||
{
|
||||
BufferClient::BufferClient(std::string ns, double check_frequency, ros::Duration timeout_padding):
|
||||
client_(ns),
|
||||
check_frequency_(check_frequency),
|
||||
timeout_padding_(timeout_padding)
|
||||
{
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped BufferClient::lookupTransform(const std::string& target_frame, const std::string& source_frame,
|
||||
const ros::Time& time, const ros::Duration timeout) const
|
||||
{
|
||||
//populate the goal message
|
||||
tf2_msgs::LookupTransformGoal goal;
|
||||
goal.target_frame = target_frame;
|
||||
goal.source_frame = source_frame;
|
||||
goal.source_time = time;
|
||||
goal.timeout = timeout;
|
||||
goal.advanced = false;
|
||||
|
||||
return processGoal(goal);
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped BufferClient::lookupTransform(const std::string& target_frame, const ros::Time& target_time,
|
||||
const std::string& source_frame, const ros::Time& source_time,
|
||||
const std::string& fixed_frame, const ros::Duration timeout) const
|
||||
{
|
||||
//populate the goal message
|
||||
tf2_msgs::LookupTransformGoal goal;
|
||||
goal.target_frame = target_frame;
|
||||
goal.source_frame = source_frame;
|
||||
goal.source_time = source_time;
|
||||
goal.timeout = timeout;
|
||||
goal.target_time = target_time;
|
||||
goal.fixed_frame = fixed_frame;
|
||||
goal.advanced = true;
|
||||
|
||||
return processGoal(goal);
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped BufferClient::processGoal(const tf2_msgs::LookupTransformGoal& goal) const
|
||||
{
|
||||
client_.sendGoal(goal);
|
||||
|
||||
//this shouldn't happen, but could in rare cases where the server hangs
|
||||
if(!client_.waitForResult(goal.timeout + timeout_padding_))
|
||||
{
|
||||
//make sure to cancel the goal the server is pursuing
|
||||
client_.cancelGoal();
|
||||
throw tf2::TimeoutException("The LookupTransform goal sent to the BufferServer did not come back in the specified time. Something is likely wrong with the server.");
|
||||
}
|
||||
|
||||
if(client_.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
|
||||
throw tf2::TimeoutException("The LookupTransform goal sent to the BufferServer did not come back with SUCCEEDED status. Something is likely wrong with the server.");
|
||||
|
||||
//process the result for errors and return it
|
||||
return processResult(*client_.getResult());
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped BufferClient::processResult(const tf2_msgs::LookupTransformResult& result) const
|
||||
{
|
||||
//if there's no error, then we'll just return the transform
|
||||
if(result.error.error != result.error.NO_ERROR){
|
||||
//otherwise, we'll have to throw the appropriate exception
|
||||
if(result.error.error == result.error.LOOKUP_ERROR)
|
||||
throw tf2::LookupException(result.error.error_string);
|
||||
|
||||
if(result.error.error == result.error.CONNECTIVITY_ERROR)
|
||||
throw tf2::ConnectivityException(result.error.error_string);
|
||||
|
||||
if(result.error.error == result.error.EXTRAPOLATION_ERROR)
|
||||
throw tf2::ExtrapolationException(result.error.error_string);
|
||||
|
||||
if(result.error.error == result.error.INVALID_ARGUMENT_ERROR)
|
||||
throw tf2::InvalidArgumentException(result.error.error_string);
|
||||
|
||||
if(result.error.error == result.error.TIMEOUT_ERROR)
|
||||
throw tf2::TimeoutException(result.error.error_string);
|
||||
|
||||
throw tf2::TransformException(result.error.error_string);
|
||||
}
|
||||
|
||||
return result.transform;
|
||||
}
|
||||
|
||||
bool BufferClient::canTransform(const std::string& target_frame, const std::string& source_frame,
|
||||
const ros::Time& time, const ros::Duration timeout, std::string* errstr) const
|
||||
{
|
||||
try
|
||||
{
|
||||
lookupTransform(target_frame, source_frame, time, timeout);
|
||||
return true;
|
||||
}
|
||||
catch(tf2::TransformException& ex)
|
||||
{
|
||||
if(errstr)
|
||||
{
|
||||
errstr->clear();
|
||||
*errstr = ex.what();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferClient::canTransform(const std::string& target_frame, const ros::Time& target_time,
|
||||
const std::string& source_frame, const ros::Time& source_time,
|
||||
const std::string& fixed_frame, const ros::Duration timeout, std::string* errstr) const
|
||||
{
|
||||
try
|
||||
{
|
||||
lookupTransform(target_frame, target_time, source_frame, source_time, fixed_frame, timeout);
|
||||
return true;
|
||||
}
|
||||
catch(tf2::TransformException& ex)
|
||||
{
|
||||
if(errstr)
|
||||
{
|
||||
errstr->clear();
|
||||
*errstr = ex.what();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
222
navigations/geometry2/tf2_ros/src/buffer_server.cpp
Executable file
222
navigations/geometry2/tf2_ros/src/buffer_server.cpp
Executable file
@@ -0,0 +1,222 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright (c) 2009, 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 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.
|
||||
*
|
||||
* Author: Eitan Marder-Eppstein
|
||||
*********************************************************************/
|
||||
#include <tf2_ros/buffer_server.h>
|
||||
|
||||
namespace tf2_ros
|
||||
{
|
||||
BufferServer::BufferServer(const Buffer& buffer, const std::string& ns, bool auto_start, ros::Duration check_period):
|
||||
buffer_(buffer),
|
||||
server_(ros::NodeHandle(),
|
||||
ns,
|
||||
boost::bind(&BufferServer::goalCB, this, boost::placeholders::_1),
|
||||
boost::bind(&BufferServer::cancelCB, this, boost::placeholders::_1),
|
||||
auto_start)
|
||||
{
|
||||
ros::NodeHandle n;
|
||||
check_timer_ = n.createTimer(check_period, boost::bind(&BufferServer::checkTransforms, this, boost::placeholders::_1));
|
||||
}
|
||||
|
||||
void BufferServer::checkTransforms(const ros::TimerEvent& e)
|
||||
{
|
||||
(void) e; //Unused
|
||||
boost::mutex::scoped_lock l(mutex_);
|
||||
for(std::list<GoalInfo>::iterator it = active_goals_.begin(); it != active_goals_.end();)
|
||||
{
|
||||
GoalInfo& info = *it;
|
||||
|
||||
//we want to lookup a transform if the time on the goal
|
||||
//has expired, or a transform is available
|
||||
if(canTransform(info.handle) || info.end_time < ros::Time::now())
|
||||
{
|
||||
tf2_msgs::LookupTransformResult result;
|
||||
|
||||
//try to populate the result, catching exceptions if they occur
|
||||
try
|
||||
{
|
||||
result.transform = lookupTransform(info.handle);
|
||||
}
|
||||
catch (tf2::ConnectivityException &ex)
|
||||
{
|
||||
result.error.error = result.error.CONNECTIVITY_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::LookupException &ex)
|
||||
{
|
||||
result.error.error = result.error.LOOKUP_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::ExtrapolationException &ex)
|
||||
{
|
||||
result.error.error = result.error.EXTRAPOLATION_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::InvalidArgumentException &ex)
|
||||
{
|
||||
result.error.error = result.error.INVALID_ARGUMENT_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::TimeoutException &ex)
|
||||
{
|
||||
result.error.error = result.error.TIMEOUT_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::TransformException &ex)
|
||||
{
|
||||
result.error.error = result.error.TRANSFORM_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
|
||||
//make sure to pass the result to the client
|
||||
//even failed transforms are considered a success
|
||||
//since the request was successfully processed
|
||||
info.handle.setSucceeded(result);
|
||||
it = active_goals_.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferServer::cancelCB(GoalHandle gh)
|
||||
{
|
||||
boost::mutex::scoped_lock l(mutex_);
|
||||
//we need to find the goal in the list and remove it... also setting it as canceled
|
||||
//if its not in the list, we won't do anything since it will have already been set
|
||||
//as completed
|
||||
for(std::list<GoalInfo>::iterator it = active_goals_.begin(); it != active_goals_.end();)
|
||||
{
|
||||
GoalInfo& info = *it;
|
||||
if(info.handle == gh)
|
||||
{
|
||||
info.handle.setCanceled();
|
||||
it = active_goals_.erase(it);
|
||||
return;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferServer::goalCB(GoalHandle gh)
|
||||
{
|
||||
//we'll accept all goals we get
|
||||
gh.setAccepted();
|
||||
|
||||
//if the transform isn't immediately available, we'll push it onto our list to check
|
||||
//along with the time that the goal will end
|
||||
GoalInfo goal_info;
|
||||
goal_info.handle = gh;
|
||||
goal_info.end_time = ros::Time::now() + gh.getGoal()->timeout;
|
||||
|
||||
//we can do a quick check here to see if the transform is valid
|
||||
//we'll also do this if the end time has been reached
|
||||
if(canTransform(gh) || goal_info.end_time <= ros::Time::now())
|
||||
{
|
||||
tf2_msgs::LookupTransformResult result;
|
||||
try
|
||||
{
|
||||
result.transform = lookupTransform(gh);
|
||||
}
|
||||
catch (tf2::ConnectivityException &ex)
|
||||
{
|
||||
result.error.error = result.error.CONNECTIVITY_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::LookupException &ex)
|
||||
{
|
||||
result.error.error = result.error.LOOKUP_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::ExtrapolationException &ex)
|
||||
{
|
||||
result.error.error = result.error.EXTRAPOLATION_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::InvalidArgumentException &ex)
|
||||
{
|
||||
result.error.error = result.error.INVALID_ARGUMENT_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::TimeoutException &ex)
|
||||
{
|
||||
result.error.error = result.error.TIMEOUT_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
catch (tf2::TransformException &ex)
|
||||
{
|
||||
result.error.error = result.error.TRANSFORM_ERROR;
|
||||
result.error.error_string = ex.what();
|
||||
}
|
||||
|
||||
gh.setSucceeded(result);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::mutex::scoped_lock l(mutex_);
|
||||
active_goals_.push_back(goal_info);
|
||||
}
|
||||
|
||||
bool BufferServer::canTransform(GoalHandle gh)
|
||||
{
|
||||
const tf2_msgs::LookupTransformGoal::ConstPtr& goal = gh.getGoal();
|
||||
|
||||
//check whether we need to used the advanced or simple api
|
||||
if(!goal->advanced)
|
||||
return buffer_.canTransform(goal->target_frame, goal->source_frame, goal->source_time);
|
||||
|
||||
return buffer_.canTransform(goal->target_frame, goal->target_time,
|
||||
goal->source_frame, goal->source_time, goal->fixed_frame);
|
||||
}
|
||||
|
||||
geometry_msgs::TransformStamped BufferServer::lookupTransform(GoalHandle gh)
|
||||
{
|
||||
const tf2_msgs::LookupTransformGoal::ConstPtr& goal = gh.getGoal();
|
||||
|
||||
//check whether we need to used the advanced or simple api
|
||||
if(!goal->advanced)
|
||||
return buffer_.lookupTransform(goal->target_frame, goal->source_frame, goal->source_time);
|
||||
|
||||
return buffer_.lookupTransform(goal->target_frame, goal->target_time,
|
||||
goal->source_frame, goal->source_time, goal->fixed_frame);
|
||||
}
|
||||
|
||||
void BufferServer::start()
|
||||
{
|
||||
server_.start();
|
||||
}
|
||||
|
||||
};
|
||||
71
navigations/geometry2/tf2_ros/src/buffer_server_main.cpp
Executable file
71
navigations/geometry2/tf2_ros/src/buffer_server_main.cpp
Executable file
@@ -0,0 +1,71 @@
|
||||
/*********************************************************************
|
||||
*
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* Copyright (c) 2009, 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 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.
|
||||
*
|
||||
* Author: Wim Meeussen
|
||||
*********************************************************************/
|
||||
#include <tf2_ros/buffer_server.h>
|
||||
#include <tf2_ros/transform_listener.h>
|
||||
#include <ros/ros.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ros::init(argc, argv, "tf_buffer");
|
||||
ros::NodeHandle nh;
|
||||
|
||||
double buffer_size;
|
||||
nh.param("buffer_size", buffer_size, 120.0);
|
||||
|
||||
bool publish_frame_service;
|
||||
nh.param("publish_frame_service", publish_frame_service, false);
|
||||
|
||||
// Legacy behavior re: #209
|
||||
bool use_node_namespace;
|
||||
nh.param("use_node_namespace", use_node_namespace, false);
|
||||
std::string node_name;
|
||||
if (use_node_namespace)
|
||||
{
|
||||
node_name = ros::this_node::getName();
|
||||
}
|
||||
else
|
||||
{
|
||||
node_name = "tf2_buffer_server";
|
||||
}
|
||||
|
||||
tf2_ros::Buffer buffer_core(ros::Duration(buffer_size), publish_frame_service);
|
||||
tf2_ros::TransformListener listener(buffer_core);
|
||||
tf2_ros::BufferServer buffer_server(buffer_core, node_name , false);
|
||||
buffer_server.start();
|
||||
|
||||
ros::spin();
|
||||
}
|
||||
64
navigations/geometry2/tf2_ros/src/static_transform_broadcaster.cpp
Executable file
64
navigations/geometry2/tf2_ros/src/static_transform_broadcaster.cpp
Executable file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/** \author Tully Foote */
|
||||
|
||||
|
||||
#include "ros/ros.h"
|
||||
#include "tf2_msgs/TFMessage.h"
|
||||
#include "tf2_ros/static_transform_broadcaster.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace tf2_ros {
|
||||
|
||||
StaticTransformBroadcaster::StaticTransformBroadcaster()
|
||||
{
|
||||
publisher_ = node_.advertise<tf2_msgs::TFMessage>("/tf_static", 100, true);
|
||||
};
|
||||
|
||||
void StaticTransformBroadcaster::sendTransform(const std::vector<geometry_msgs::TransformStamped> & msgtf)
|
||||
{
|
||||
for (const geometry_msgs::TransformStamped& input : msgtf)
|
||||
{
|
||||
auto predicate = [&input](const geometry_msgs::TransformStamped existing) {
|
||||
return input.child_frame_id == existing.child_frame_id;
|
||||
};
|
||||
auto existing = std::find_if(net_message_.transforms.begin(), net_message_.transforms.end(), predicate);
|
||||
|
||||
if (existing != net_message_.transforms.end())
|
||||
*existing = input;
|
||||
else
|
||||
net_message_.transforms.push_back(input);
|
||||
}
|
||||
|
||||
publisher_.publish(net_message_);
|
||||
}
|
||||
|
||||
}
|
||||
145
navigations/geometry2/tf2_ros/src/static_transform_broadcaster_program.cpp
Executable file
145
navigations/geometry2/tf2_ros/src/static_transform_broadcaster_program.cpp
Executable file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <tf2/LinearMath/Quaternion.h>
|
||||
#include "tf2_ros/static_transform_broadcaster.h"
|
||||
|
||||
|
||||
bool validateXmlRpcTf(XmlRpc::XmlRpcValue tf_data) {
|
||||
// Validate a TF stored in XML RPC format: ensures the appropriate fields
|
||||
// exist. Note this does not check data types.
|
||||
return tf_data.hasMember("child_frame_id") &&
|
||||
tf_data.hasMember("header") &&
|
||||
tf_data["header"].hasMember("frame_id") &&
|
||||
tf_data.hasMember("transform") &&
|
||||
tf_data["transform"].hasMember("translation") &&
|
||||
tf_data["transform"]["translation"].hasMember("x") &&
|
||||
tf_data["transform"]["translation"].hasMember("y") &&
|
||||
tf_data["transform"]["translation"].hasMember("z") &&
|
||||
tf_data["transform"].hasMember("rotation") &&
|
||||
tf_data["transform"]["rotation"].hasMember("x") &&
|
||||
tf_data["transform"]["rotation"].hasMember("y") &&
|
||||
tf_data["transform"]["rotation"].hasMember("z") &&
|
||||
tf_data["transform"]["rotation"].hasMember("w");
|
||||
};
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
//Initialize ROS
|
||||
ros::init(argc, argv,"static_transform_publisher", ros::init_options::AnonymousName);
|
||||
tf2_ros::StaticTransformBroadcaster broadcaster;
|
||||
geometry_msgs::TransformStamped msg;
|
||||
|
||||
if(argc == 10)
|
||||
{
|
||||
msg.transform.translation.x = atof(argv[1]);
|
||||
msg.transform.translation.y = atof(argv[2]);
|
||||
msg.transform.translation.z = atof(argv[3]);
|
||||
msg.transform.rotation.x = atof(argv[4]);
|
||||
msg.transform.rotation.y = atof(argv[5]);
|
||||
msg.transform.rotation.z = atof(argv[6]);
|
||||
msg.transform.rotation.w = atof(argv[7]);
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.header.frame_id = argv[8];
|
||||
msg.child_frame_id = argv[9];
|
||||
}
|
||||
else if (argc == 9)
|
||||
{
|
||||
msg.transform.translation.x = atof(argv[1]);
|
||||
msg.transform.translation.y = atof(argv[2]);
|
||||
msg.transform.translation.z = atof(argv[3]);
|
||||
|
||||
tf2::Quaternion quat;
|
||||
quat.setRPY(atof(argv[6]), atof(argv[5]), atof(argv[4]));
|
||||
msg.transform.rotation.x = quat.x();
|
||||
msg.transform.rotation.y = quat.y();
|
||||
msg.transform.rotation.z = quat.z();
|
||||
msg.transform.rotation.w = quat.w();
|
||||
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.header.frame_id = argv[7];
|
||||
msg.child_frame_id = argv[8];
|
||||
}
|
||||
else if (argc == 2) {
|
||||
const std::string param_name = argv[1];
|
||||
ROS_INFO_STREAM("Looking for TF in parameter: " << param_name);
|
||||
XmlRpc::XmlRpcValue tf_data;
|
||||
|
||||
if (!ros::param::has(param_name) || !ros::param::get(param_name, tf_data)) {
|
||||
ROS_FATAL_STREAM("Could not read TF from parameter server: " << param_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check that all required members are present & of the right type.
|
||||
if (!validateXmlRpcTf(tf_data)) {
|
||||
ROS_FATAL_STREAM("Could not validate XmlRpcC for TF data: " << tf_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.transform.translation.x = (double) tf_data["transform"]["translation"]["x"];
|
||||
msg.transform.translation.y = (double) tf_data["transform"]["translation"]["y"];
|
||||
msg.transform.translation.z = (double) tf_data["transform"]["translation"]["z"];
|
||||
msg.transform.rotation.x = (double) tf_data["transform"]["rotation"]["x"];
|
||||
msg.transform.rotation.y = (double) tf_data["transform"]["rotation"]["y"];
|
||||
msg.transform.rotation.z = (double) tf_data["transform"]["rotation"]["z"];
|
||||
msg.transform.rotation.w = (double) tf_data["transform"]["rotation"]["w"];
|
||||
msg.header.stamp = ros::Time::now();
|
||||
msg.header.frame_id = (std::string) tf_data["header"]["frame_id"];
|
||||
msg.child_frame_id = (std::string) tf_data["child_frame_id"];
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("A command line utility for manually sending a transform.\n");
|
||||
//printf("It will periodicaly republish the given transform. \n");
|
||||
printf("Usage: static_transform_publisher x y z qx qy qz qw frame_id child_frame_id \n");
|
||||
printf("OR \n");
|
||||
printf("Usage: static_transform_publisher x y z yaw pitch roll frame_id child_frame_id \n");
|
||||
printf("OR \n");
|
||||
printf("Usage: static_transform_publisher /param_name \n");
|
||||
printf("\nThis transform is the transform of the coordinate frame from frame_id into the coordinate frame \n");
|
||||
printf("of the child_frame_id. \n");
|
||||
ROS_ERROR("static_transform_publisher exited due to not having the right number of arguments");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Checks: frames should not be the same.
|
||||
if (msg.header.frame_id == msg.child_frame_id)
|
||||
{
|
||||
ROS_FATAL("target_frame and source frame are the same (%s, %s) this cannot work",
|
||||
msg.header.frame_id.c_str(), msg.child_frame_id.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
broadcaster.sendTransform(msg);
|
||||
ROS_INFO("Spinning until killed publishing %s to %s",
|
||||
msg.header.frame_id.c_str(), msg.child_frame_id.c_str());
|
||||
ros::spin();
|
||||
return 0;
|
||||
};
|
||||
44
navigations/geometry2/tf2_ros/src/tf2_ros/__init__.py
Executable file
44
navigations/geometry2/tf2_ros/src/tf2_ros/__init__.py
Executable file
@@ -0,0 +1,44 @@
|
||||
#! /usr/bin/python
|
||||
#***********************************************************
|
||||
#* Software License Agreement (BSD License)
|
||||
#*
|
||||
#* Copyright (c) 2009, 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 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.
|
||||
#*
|
||||
#* Author: Eitan Marder-Eppstein
|
||||
#***********************************************************
|
||||
from __future__ import absolute_import
|
||||
from tf2_py import *
|
||||
from .buffer_interface import *
|
||||
from .buffer import *
|
||||
from .buffer_client import *
|
||||
from .transform_listener import *
|
||||
from .transform_broadcaster import *
|
||||
from .static_transform_broadcaster import *
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
162
navigations/geometry2/tf2_ros/src/tf2_ros/buffer.py
Executable file
162
navigations/geometry2/tf2_ros/src/tf2_ros/buffer.py
Executable file
@@ -0,0 +1,162 @@
|
||||
# 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.
|
||||
|
||||
# author: Wim Meeussen
|
||||
|
||||
import rospy
|
||||
import tf2_py as tf2
|
||||
import tf2_ros
|
||||
from tf2_msgs.srv import FrameGraph, FrameGraphResponse
|
||||
import rosgraph.masterapi
|
||||
|
||||
DEFAULT_CAN_TRANSFORM_POLLING_SCALE = 0.01
|
||||
|
||||
class Buffer(tf2.BufferCore, tf2_ros.BufferInterface):
|
||||
"""
|
||||
Standard implementation of the :class:`tf2_ros.BufferInterface` abstract data type.
|
||||
|
||||
Inherits from :class:`tf2_ros.buffer_interface.BufferInterface` and :class:`tf2.BufferCore`.
|
||||
|
||||
Stores known frames and optionally offers a ROS service, "tf2_frames", which responds to client requests
|
||||
with a response containing a :class:`tf2_msgs.FrameGraph` representing the relationship of
|
||||
known frames.
|
||||
"""
|
||||
|
||||
def __init__(self, cache_time = None, debug = True):
|
||||
"""
|
||||
.. function:: __init__(cache_time = None, debug = True)
|
||||
|
||||
Constructor.
|
||||
|
||||
:param cache_time: (Optional) How long to retain past information in BufferCore.
|
||||
:param debug: (Optional) If true, check if another tf2_frames service has been advertised.
|
||||
"""
|
||||
if cache_time != None:
|
||||
tf2.BufferCore.__init__(self, cache_time)
|
||||
else:
|
||||
tf2.BufferCore.__init__(self)
|
||||
tf2_ros.BufferInterface.__init__(self)
|
||||
|
||||
if debug:
|
||||
#Check to see if the service has already been advertised in this node
|
||||
try:
|
||||
m = rosgraph.masterapi.Master(rospy.get_name())
|
||||
m.lookupService('~tf2_frames')
|
||||
except (rosgraph.masterapi.Error, rosgraph.masterapi.Failure):
|
||||
self.frame_server = rospy.Service('~tf2_frames', FrameGraph, self.__get_frames)
|
||||
|
||||
self.CAN_TRANSFORM_POLLING_SCALE = DEFAULT_CAN_TRANSFORM_POLLING_SCALE
|
||||
|
||||
def __get_frames(self, req):
|
||||
return FrameGraphResponse(self.all_frames_as_yaml())
|
||||
|
||||
def lookup_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
|
||||
self.can_transform(target_frame, source_frame, time, timeout)
|
||||
return self.lookup_transform_core(target_frame, source_frame, time)
|
||||
|
||||
def lookup_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame using the advanced API.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
self.can_transform_full(target_frame, target_time, source_frame, source_time, fixed_frame, timeout)
|
||||
return self.lookup_transform_full_core(target_frame, target_time, source_frame, source_time, fixed_frame)
|
||||
|
||||
|
||||
def can_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0), return_debug_tuple=False):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param return_debug_type: (Optional) If true, return a tuple representing debug information.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
if timeout != rospy.Duration(0.0):
|
||||
start_time = rospy.Time.now()
|
||||
polling_interval = timeout * self.CAN_TRANSFORM_POLLING_SCALE
|
||||
while (rospy.Time.now() < start_time + timeout and
|
||||
not self.can_transform_core(target_frame, source_frame, time)[0] and
|
||||
(rospy.Time.now()+rospy.Duration(3.0)) >= start_time): # big jumps in time are likely bag loops, so break for them
|
||||
rospy.sleep(polling_interval)
|
||||
core_result = self.can_transform_core(target_frame, source_frame, time)
|
||||
if return_debug_tuple:
|
||||
return core_result
|
||||
return core_result[0]
|
||||
|
||||
def can_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0),
|
||||
|
||||
return_debug_tuple=False):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible (advanced API).
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param return_debug_type: (Optional) If true, return a tuple representing debug information.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
if timeout != rospy.Duration(0.0):
|
||||
start_time = rospy.Time.now()
|
||||
polling_interval = timeout * self.CAN_TRANSFORM_POLLING_SCALE
|
||||
while (rospy.Time.now() < start_time + timeout and
|
||||
not self.can_transform_full_core(target_frame, target_time, source_frame, source_time, fixed_frame)[0] and
|
||||
(rospy.Time.now()+rospy.Duration(3.0)) >= start_time): # big jumps in time are likely bag loops, so break for them
|
||||
rospy.sleep(polling_interval)
|
||||
core_result = self.can_transform_full_core(target_frame, target_time, source_frame, source_time, fixed_frame)
|
||||
if return_debug_tuple:
|
||||
return core_result
|
||||
return core_result[0]
|
||||
|
||||
196
navigations/geometry2/tf2_ros/src/tf2_ros/buffer_client.py
Executable file
196
navigations/geometry2/tf2_ros/src/tf2_ros/buffer_client.py
Executable file
@@ -0,0 +1,196 @@
|
||||
#! /usr/bin/python
|
||||
#***********************************************************
|
||||
#* Software License Agreement (BSD License)
|
||||
#*
|
||||
#* Copyright (c) 2009, 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 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.
|
||||
#*
|
||||
#* Author: Eitan Marder-Eppstein
|
||||
#***********************************************************
|
||||
import rospy
|
||||
import actionlib
|
||||
import tf2_py as tf2
|
||||
import tf2_ros
|
||||
|
||||
from tf2_msgs.msg import LookupTransformAction, LookupTransformGoal
|
||||
from actionlib_msgs.msg import GoalStatus
|
||||
|
||||
class BufferClient(tf2_ros.BufferInterface):
|
||||
"""
|
||||
Action client-based implementation of BufferInterface.
|
||||
"""
|
||||
def __init__(self, ns, check_frequency = None, timeout_padding = rospy.Duration.from_sec(2.0)):
|
||||
"""
|
||||
.. function:: __init__(ns, check_frequency = None, timeout_padding = rospy.Duration.from_sec(2.0))
|
||||
|
||||
Constructor.
|
||||
|
||||
:param ns: The namespace in which to look for a BufferServer.
|
||||
:param check_frequency: How frequently to check for updates to known transforms.
|
||||
:param timeout_padding: A constant timeout to add to blocking calls.
|
||||
"""
|
||||
tf2_ros.BufferInterface.__init__(self)
|
||||
self.client = actionlib.SimpleActionClient(ns, LookupTransformAction)
|
||||
self.timeout_padding = timeout_padding
|
||||
|
||||
if check_frequency is not None:
|
||||
rospy.logwarn('Argument check_frequency is deprecated and should not be used.')
|
||||
|
||||
def wait_for_server(self, timeout = rospy.Duration()):
|
||||
"""
|
||||
Block until the action server is ready to respond to requests.
|
||||
|
||||
:param timeout: Time to wait for the server.
|
||||
:return: True if the server is ready, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
return self.client.wait_for_server(timeout)
|
||||
|
||||
# lookup, simple api
|
||||
def lookup_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
goal = LookupTransformGoal()
|
||||
goal.target_frame = target_frame;
|
||||
goal.source_frame = source_frame;
|
||||
goal.source_time = time;
|
||||
goal.timeout = timeout;
|
||||
goal.advanced = False;
|
||||
|
||||
return self.__process_goal(goal)
|
||||
|
||||
# lookup, advanced api
|
||||
def lookup_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame using the advanced API.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
goal = LookupTransformGoal()
|
||||
goal.target_frame = target_frame;
|
||||
goal.source_frame = source_frame;
|
||||
goal.source_time = source_time;
|
||||
goal.timeout = timeout;
|
||||
goal.target_time = target_time;
|
||||
goal.fixed_frame = fixed_frame;
|
||||
goal.advanced = True;
|
||||
|
||||
return self.__process_goal(goal)
|
||||
|
||||
# can, simple api
|
||||
def can_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param return_debug_type: (Optional) If true, return a tuple representing debug information.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
try:
|
||||
self.lookup_transform(target_frame, source_frame, time, timeout)
|
||||
return True
|
||||
except tf2.TransformException:
|
||||
return False
|
||||
|
||||
|
||||
# can, advanced api
|
||||
def can_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible (advanced API).
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param return_debug_type: (Optional) If true, return a tuple representing debug information.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
try:
|
||||
self.lookup_transform_full(target_frame, target_time, source_frame, source_time, fixed_frame, timeout)
|
||||
return True
|
||||
except tf2.TransformException:
|
||||
return False
|
||||
|
||||
def __process_goal(self, goal):
|
||||
self.client.send_goal(goal)
|
||||
|
||||
if not self.client.wait_for_result(goal.timeout + self.timeout_padding):
|
||||
#This shouldn't happen, but could in rare cases where the server hangs
|
||||
raise tf2.TimeoutException("The LookupTransform goal sent to the BufferServer did not come back in the specified time. Something is likely wrong with the server")
|
||||
|
||||
if self.client.get_state() != GoalStatus.SUCCEEDED:
|
||||
raise tf2.TimeoutException("The LookupTransform goal sent to the BufferServer did not come back with SUCCEEDED status. Something is likely wrong with the server.")
|
||||
|
||||
return self.__process_result(self.client.get_result())
|
||||
|
||||
def __process_result(self, result):
|
||||
if not result:
|
||||
raise tf2.TransformException("The BufferServer returned None for result! Something is likely wrong with the server.")
|
||||
if not result.error:
|
||||
raise tf2.TransformException("The BufferServer returned None for result.error! Something is likely wrong with the server.")
|
||||
if result.error.error != result.error.NO_ERROR:
|
||||
if result.error.error == result.error.LOOKUP_ERROR:
|
||||
raise tf2.LookupException(result.error.error_string)
|
||||
if result.error.error == result.error.CONNECTIVITY_ERROR:
|
||||
raise tf2.ConnectivityException(result.error.error_string)
|
||||
if result.error.error == result.error.EXTRAPOLATION_ERROR:
|
||||
raise tf2.ExtrapolationException(result.error.error_string)
|
||||
if result.error.error == result.error.INVALID_ARGUMENT_ERROR:
|
||||
raise tf2.InvalidArgumentException(result.error.error_string)
|
||||
if result.error.error == result.error.TIMEOUT_ERROR:
|
||||
raise tf2.TimeoutException(result.error.error_string)
|
||||
|
||||
raise tf2.TransformException(result.error.error_string)
|
||||
|
||||
return result.transform
|
||||
251
navigations/geometry2/tf2_ros/src/tf2_ros/buffer_interface.py
Executable file
251
navigations/geometry2/tf2_ros/src/tf2_ros/buffer_interface.py
Executable file
@@ -0,0 +1,251 @@
|
||||
# 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.
|
||||
|
||||
# author: Wim Meeussen
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import rospy
|
||||
import tf2_py as tf2
|
||||
import tf2_ros
|
||||
from copy import deepcopy
|
||||
from std_msgs.msg import Header
|
||||
|
||||
class BufferInterface:
|
||||
"""
|
||||
Abstract interface for wrapping the Python bindings for the tf2 library in
|
||||
a ROS-based convenience API.
|
||||
Implementations include :class:tf2_ros.buffer.Buffer and
|
||||
:class:tf2_ros.buffer_client.BufferClient.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.registration = tf2_ros.TransformRegistration()
|
||||
|
||||
# transform, simple api
|
||||
def transform(self, object_stamped, target_frame, timeout=rospy.Duration(0.0), new_type = None):
|
||||
"""
|
||||
Transform an input into the target frame.
|
||||
|
||||
The input must be a known transformable type (by way of the tf2 data type conversion interface).
|
||||
|
||||
If new_type is not None, the type specified must have a valid conversion from the input type,
|
||||
else the function will raise an exception.
|
||||
|
||||
:param object_stamped: The timestamped object the transform.
|
||||
:param target_frame: Name of the frame to transform the input into.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param new_type: (Optional) Type to convert the object to.
|
||||
:return: The transformed, timestamped output, possibly converted to a new type.
|
||||
"""
|
||||
do_transform = self.registration.get(type(object_stamped))
|
||||
res = do_transform(object_stamped, self.lookup_transform(target_frame, object_stamped.header.frame_id,
|
||||
object_stamped.header.stamp, timeout))
|
||||
if not new_type:
|
||||
return res
|
||||
|
||||
return convert(res, new_type)
|
||||
|
||||
# transform, advanced api
|
||||
def transform_full(self, object_stamped, target_frame, target_time, fixed_frame, timeout=rospy.Duration(0.0), new_type = None):
|
||||
"""
|
||||
Transform an input into the target frame (advanced API).
|
||||
|
||||
The input must be a known transformable type (by way of the tf2 data type conversion interface).
|
||||
|
||||
If new_type is not None, the type specified must have a valid conversion from the input type,
|
||||
else the function will raise an exception.
|
||||
|
||||
This function follows the advanced API, which allows tranforming between different time points,
|
||||
as well as specifying a frame to be considered fixed in time.
|
||||
|
||||
:param object_stamped: The timestamped object the transform.
|
||||
:param target_frame: Name of the frame to transform the input into.
|
||||
:param target_time: Time to transform the input into.
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:param new_type: (Optional) Type to convert the object to.
|
||||
:return: The transformed, timestamped output, possibly converted to a new type.
|
||||
"""
|
||||
do_transform = self.registration.get(type(object_stamped))
|
||||
res = do_transform(object_stamped, self.lookup_transform_full(target_frame, target_time,
|
||||
object_stamped.header.frame_id, object_stamped.header.stamp,
|
||||
fixed_frame, timeout))
|
||||
if not new_type:
|
||||
return res
|
||||
|
||||
return convert(res, new_type)
|
||||
|
||||
def lookup_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame.
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
raise NotImplementedException()
|
||||
|
||||
def lookup_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Get the transform from the source frame to the target frame using the advanced API.
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: The transform between the frames.
|
||||
:rtype: :class:`geometry_msgs.msg.TransformStamped`
|
||||
"""
|
||||
raise NotImplementedException()
|
||||
|
||||
# can, simple api
|
||||
def can_transform(self, target_frame, source_frame, time, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible.
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param source_frame: Name of the input frame.
|
||||
:param time: The time at which to get the transform. (0 will get the latest)
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
raise NotImplementedException()
|
||||
|
||||
# can, advanced api
|
||||
def can_transform_full(self, target_frame, target_time, source_frame, source_time, fixed_frame, timeout=rospy.Duration(0.0)):
|
||||
"""
|
||||
Check if a transform from the source frame to the target frame is possible (advanced API).
|
||||
|
||||
Must be implemented by a subclass of BufferInterface.
|
||||
|
||||
:param target_frame: Name of the frame to transform into.
|
||||
:param target_time: The time to transform to. (0 will get the latest)
|
||||
:param source_frame: Name of the input frame.
|
||||
:param source_time: The time at which source_frame will be evaluated. (0 will get the latest)
|
||||
:param fixed_frame: Name of the frame to consider constant in time.
|
||||
:param timeout: (Optional) Time to wait for the target frame to become available.
|
||||
:return: True if the transform is possible, false otherwise.
|
||||
:rtype: bool
|
||||
"""
|
||||
raise NotImplementedException()
|
||||
|
||||
|
||||
def Stamped(obj, stamp, frame_id):
|
||||
obj.header = Header(frame_id=frame_id, stamp=stamp)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
class TypeException(Exception):
|
||||
"""
|
||||
Raised when an unexpected type is received while registering a transform
|
||||
in :class:`tf2_ros.buffer_interface.BufferInterface`.
|
||||
"""
|
||||
def __init__(self, errstr):
|
||||
self.errstr = errstr
|
||||
|
||||
class NotImplementedException(Exception):
|
||||
"""
|
||||
Raised when can_transform or lookup_transform is not implemented in a
|
||||
subclass of :class:`tf2_ros.buffer_interface.BufferInterface`.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.errstr = 'CanTransform or LookupTransform not implemented'
|
||||
|
||||
|
||||
class TransformRegistration():
|
||||
__type_map = {}
|
||||
|
||||
def print_me(self):
|
||||
print(TransformRegistration.__type_map)
|
||||
|
||||
def add(self, key, callback):
|
||||
TransformRegistration.__type_map[key] = callback
|
||||
|
||||
def get(self, key):
|
||||
if not key in TransformRegistration.__type_map:
|
||||
raise TypeException('Type %s if not loaded or supported'% str(key))
|
||||
else:
|
||||
return TransformRegistration.__type_map[key]
|
||||
|
||||
class ConvertRegistration():
|
||||
__to_msg_map = {}
|
||||
__from_msg_map = {}
|
||||
__convert_map = {}
|
||||
|
||||
def add_from_msg(self, key, callback):
|
||||
ConvertRegistration.__from_msg_map[key] = callback
|
||||
|
||||
def add_to_msg(self, key, callback):
|
||||
ConvertRegistration.__to_msg_map[key] = callback
|
||||
|
||||
def add_convert(self, key, callback):
|
||||
ConvertRegistration.__convert_map[key] = callback
|
||||
|
||||
def get_from_msg(self, key):
|
||||
if not key in ConvertRegistration.__from_msg_map:
|
||||
raise TypeException('Type %s if not loaded or supported'% str(key))
|
||||
else:
|
||||
return ConvertRegistration.__from_msg_map[key]
|
||||
|
||||
def get_to_msg(self, key):
|
||||
if not key in ConvertRegistration.__to_msg_map:
|
||||
raise TypeException('Type %s if not loaded or supported'%str(key))
|
||||
else:
|
||||
return ConvertRegistration.__to_msg_map[key]
|
||||
|
||||
def get_convert(self, key):
|
||||
if not key in ConvertRegistration.__convert_map:
|
||||
raise TypeException("Type %s if not loaded or supported" % str(key))
|
||||
else:
|
||||
return ConvertRegistration.__convert_map[key]
|
||||
|
||||
def convert(a, b_type):
|
||||
c = ConvertRegistration()
|
||||
#check if an efficient conversion function between the types exists
|
||||
try:
|
||||
f = c.get_convert((type(a), b_type))
|
||||
return f(a)
|
||||
except TypeException:
|
||||
if type(a) == b_type:
|
||||
return deepcopy(a)
|
||||
|
||||
f_to = c.get_to_msg(type(a))
|
||||
f_from = c.get_from_msg(b_type)
|
||||
return f_from(f_to(a))
|
||||
51
navigations/geometry2/tf2_ros/src/tf2_ros/static_transform_broadcaster.py
Executable file
51
navigations/geometry2/tf2_ros/src/tf2_ros/static_transform_broadcaster.py
Executable file
@@ -0,0 +1,51 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# 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 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.
|
||||
|
||||
import rospy
|
||||
from tf2_msgs.msg import TFMessage
|
||||
from geometry_msgs.msg import TransformStamped
|
||||
|
||||
|
||||
class StaticTransformBroadcaster(object):
|
||||
"""
|
||||
:class:`StaticTransformBroadcaster` is a convenient way to send static transformation on the ``"/tf_static"`` message topic.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.pub_tf = rospy.Publisher("/tf_static", TFMessage, queue_size=100, latch=True)
|
||||
|
||||
def sendTransform(self, transform):
|
||||
if not isinstance(transform, list):
|
||||
transform = [transform]
|
||||
self.pub_tf.publish(TFMessage(transform))
|
||||
|
||||
|
||||
56
navigations/geometry2/tf2_ros/src/tf2_ros/transform_broadcaster.py
Executable file
56
navigations/geometry2/tf2_ros/src/tf2_ros/transform_broadcaster.py
Executable file
@@ -0,0 +1,56 @@
|
||||
# Software License Agreement (BSD License)
|
||||
#
|
||||
# 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 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.
|
||||
|
||||
import rospy
|
||||
from tf2_msgs.msg import TFMessage
|
||||
from geometry_msgs.msg import TransformStamped
|
||||
|
||||
|
||||
class TransformBroadcaster:
|
||||
"""
|
||||
:class:`TransformBroadcaster` is a convenient way to send transformation updates on the ``"/tf"`` message topic.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.pub_tf = rospy.Publisher("/tf", TFMessage, queue_size=100)
|
||||
|
||||
def sendTransform(self, transform):
|
||||
"""
|
||||
Send a transform, or a list of transforms, to the Buffer associated with this TransformBroadcaster.
|
||||
|
||||
:param transform: A transform or list of transforms to send.
|
||||
"""
|
||||
if not isinstance(transform, list):
|
||||
transform = [transform]
|
||||
self.pub_tf.publish(TFMessage(transform))
|
||||
|
||||
|
||||
89
navigations/geometry2/tf2_ros/src/tf2_ros/transform_listener.py
Executable file
89
navigations/geometry2/tf2_ros/src/tf2_ros/transform_listener.py
Executable file
@@ -0,0 +1,89 @@
|
||||
# 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.
|
||||
|
||||
# author: Wim Meeussen
|
||||
|
||||
import threading
|
||||
|
||||
import rospy
|
||||
from tf2_msgs.msg import TFMessage
|
||||
|
||||
|
||||
class TransformListener:
|
||||
"""
|
||||
:class:`TransformListener` is a convenient way to listen for coordinate frame transformation info.
|
||||
This class takes an object that instantiates the :class:`BufferInterface` interface, to which
|
||||
it propagates changes to the tf frame graph.
|
||||
"""
|
||||
def __init__(self, buffer, queue_size=None, buff_size=65536, tcp_nodelay=False):
|
||||
"""
|
||||
.. function:: __init__(buffer, queue_size=None, buff_size=65536, tcp_nodelay=False):
|
||||
|
||||
Constructor.
|
||||
|
||||
:param buffer: The buffer to propagate changes to when tf info updates.
|
||||
:param queue_size: Maximum number of messages to receive at a time. This will generally be 1 or None (infinite, default). buff_size should be increased if this parameter is set as incoming data still needs to sit in the incoming buffer before being discarded. Setting queue_size buff_size to a non-default value affects all subscribers to this topic in this process.
|
||||
:param buff_size: Incoming message buffer size in bytes. If queue_size is set, this should be set to a number greater than the queue_size times the average message size. Setting buff_size to a non-default value affects all subscribers to this topic in this process.
|
||||
:param tcp_nodelay: If True, request TCP_NODELAY from publisher. Use of this option is not generally recommended in most cases as it is better to rely on timestamps in message data. Setting tcp_nodelay to True enables TCP_NODELAY for all subscribers in the same python process.
|
||||
"""
|
||||
self.buffer = buffer
|
||||
self.last_update = rospy.Time.now()
|
||||
self.last_update_lock = threading.Lock()
|
||||
self.tf_sub = rospy.Subscriber("/tf", TFMessage, self.callback, queue_size=queue_size, buff_size=buff_size, tcp_nodelay=tcp_nodelay)
|
||||
self.tf_static_sub = rospy.Subscriber("/tf_static", TFMessage, self.static_callback, queue_size=queue_size, buff_size=buff_size, tcp_nodelay=tcp_nodelay)
|
||||
|
||||
def __del__(self):
|
||||
self.unregister()
|
||||
|
||||
def unregister(self):
|
||||
"""
|
||||
Unregisters all tf subscribers.
|
||||
"""
|
||||
self.tf_sub.unregister()
|
||||
self.tf_static_sub.unregister()
|
||||
|
||||
def check_for_reset(self):
|
||||
# Lock to prevent different threads racing on this test and update.
|
||||
# https://github.com/ros/geometry2/issues/341
|
||||
with self.last_update_lock:
|
||||
now = rospy.Time.now()
|
||||
if now < self.last_update:
|
||||
rospy.logwarn("Detected jump back in time of %fs. Clearing TF buffer." % (self.last_update - now).to_sec())
|
||||
self.buffer.clear()
|
||||
self.last_update = now
|
||||
|
||||
def callback(self, data):
|
||||
self.check_for_reset()
|
||||
who = data._connection_header.get('callerid', "default_authority")
|
||||
for transform in data.transforms:
|
||||
self.buffer.set_transform(transform, who)
|
||||
|
||||
def static_callback(self, data):
|
||||
self.check_for_reset()
|
||||
who = data._connection_header.get('callerid', "default_authority")
|
||||
for transform in data.transforms:
|
||||
self.buffer.set_transform_static(transform, who)
|
||||
66
navigations/geometry2/tf2_ros/src/transform_broadcaster.cpp
Executable file
66
navigations/geometry2/tf2_ros/src/transform_broadcaster.cpp
Executable file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/** \author Tully Foote */
|
||||
|
||||
|
||||
#include "ros/ros.h"
|
||||
#include "tf2_msgs/TFMessage.h"
|
||||
#include "tf2_ros/transform_broadcaster.h"
|
||||
|
||||
namespace tf2_ros {
|
||||
|
||||
TransformBroadcaster::TransformBroadcaster()
|
||||
{
|
||||
publisher_ = node_.advertise<tf2_msgs::TFMessage>("/tf", 100);
|
||||
};
|
||||
|
||||
void TransformBroadcaster::sendTransform(const geometry_msgs::TransformStamped & msgtf)
|
||||
{
|
||||
std::vector<geometry_msgs::TransformStamped> v1;
|
||||
v1.push_back(msgtf);
|
||||
sendTransform(v1);
|
||||
}
|
||||
|
||||
|
||||
void TransformBroadcaster::sendTransform(const std::vector<geometry_msgs::TransformStamped> & msgtf)
|
||||
{
|
||||
tf2_msgs::TFMessage message;
|
||||
for (std::vector<geometry_msgs::TransformStamped>::const_iterator it = msgtf.begin(); it != msgtf.end(); ++it)
|
||||
{
|
||||
message.transforms.push_back(*it);
|
||||
}
|
||||
publisher_.publish(message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
136
navigations/geometry2/tf2_ros/src/transform_listener.cpp
Executable file
136
navigations/geometry2/tf2_ros/src/transform_listener.cpp
Executable file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** \author Tully Foote */
|
||||
|
||||
#include "tf2_ros/transform_listener.h"
|
||||
|
||||
|
||||
using namespace tf2_ros;
|
||||
|
||||
|
||||
TransformListener::TransformListener(tf2::BufferCore& buffer, bool spin_thread, ros::TransportHints transport_hints):
|
||||
dedicated_listener_thread_(NULL), buffer_(buffer), using_dedicated_thread_(false), transport_hints_(transport_hints)
|
||||
{
|
||||
if (spin_thread)
|
||||
initWithThread();
|
||||
else
|
||||
init();
|
||||
}
|
||||
|
||||
TransformListener::TransformListener(tf2::BufferCore& buffer, const ros::NodeHandle& nh, bool spin_thread,
|
||||
ros::TransportHints transport_hints)
|
||||
: dedicated_listener_thread_(NULL)
|
||||
, node_(nh)
|
||||
, buffer_(buffer)
|
||||
, using_dedicated_thread_(false)
|
||||
, transport_hints_(transport_hints)
|
||||
{
|
||||
if (spin_thread)
|
||||
initWithThread();
|
||||
else
|
||||
init();
|
||||
}
|
||||
|
||||
TransformListener::~TransformListener()
|
||||
{
|
||||
using_dedicated_thread_ = false;
|
||||
if (dedicated_listener_thread_)
|
||||
{
|
||||
dedicated_listener_thread_->join();
|
||||
delete dedicated_listener_thread_;
|
||||
}
|
||||
}
|
||||
|
||||
void TransformListener::init()
|
||||
{
|
||||
message_subscriber_tf_ = node_.subscribe<tf2_msgs::TFMessage>("/tf", 100, boost::bind(&TransformListener::subscription_callback, this, boost::placeholders::_1), ros::VoidConstPtr(), transport_hints_); ///\todo magic number
|
||||
message_subscriber_tf_static_ = node_.subscribe<tf2_msgs::TFMessage>("/tf_static", 100, boost::bind(&TransformListener::static_subscription_callback, this, boost::placeholders::_1)); ///\todo magic number
|
||||
}
|
||||
|
||||
void TransformListener::initWithThread()
|
||||
{
|
||||
using_dedicated_thread_ = true;
|
||||
ros::SubscribeOptions ops_tf = ros::SubscribeOptions::create<tf2_msgs::TFMessage>("/tf", 100, boost::bind(&TransformListener::subscription_callback, this, boost::placeholders::_1), ros::VoidPtr(), &tf_message_callback_queue_); ///\todo magic number
|
||||
ops_tf.transport_hints = transport_hints_;
|
||||
message_subscriber_tf_ = node_.subscribe(ops_tf);
|
||||
|
||||
ros::SubscribeOptions ops_tf_static = ros::SubscribeOptions::create<tf2_msgs::TFMessage>("/tf_static", 100, boost::bind(&TransformListener::static_subscription_callback, this, boost::placeholders::_1), ros::VoidPtr(), &tf_message_callback_queue_); ///\todo magic number
|
||||
message_subscriber_tf_static_ = node_.subscribe(ops_tf_static);
|
||||
|
||||
dedicated_listener_thread_ = new boost::thread(boost::bind(&TransformListener::dedicatedListenerThread, this));
|
||||
|
||||
//Tell the buffer we have a dedicated thread to enable timeouts
|
||||
buffer_.setUsingDedicatedThread(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TransformListener::subscription_callback(const ros::MessageEvent<tf2_msgs::TFMessage const>& msg_evt)
|
||||
{
|
||||
subscription_callback_impl(msg_evt, false);
|
||||
}
|
||||
void TransformListener::static_subscription_callback(const ros::MessageEvent<tf2_msgs::TFMessage const>& msg_evt)
|
||||
{
|
||||
subscription_callback_impl(msg_evt, true);
|
||||
}
|
||||
|
||||
void TransformListener::subscription_callback_impl(const ros::MessageEvent<tf2_msgs::TFMessage const>& msg_evt, bool is_static)
|
||||
{
|
||||
ros::Time now = ros::Time::now();
|
||||
if(now < last_update_){
|
||||
ROS_WARN_STREAM("Detected jump back in time of " << (last_update_ - now).toSec() << "s. Clearing TF buffer.");
|
||||
buffer_.clear();
|
||||
}
|
||||
last_update_ = now;
|
||||
|
||||
|
||||
|
||||
const tf2_msgs::TFMessage& msg_in = *(msg_evt.getConstMessage());
|
||||
std::string authority = msg_evt.getPublisherName(); // lookup the authority
|
||||
for (unsigned int i = 0; i < msg_in.transforms.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
buffer_.setTransform(msg_in.transforms[i], authority, is_static);
|
||||
}
|
||||
|
||||
catch (tf2::TransformException& ex)
|
||||
{
|
||||
///\todo Use error reporting
|
||||
std::string temp = ex.what();
|
||||
ROS_ERROR("Failure to set recieved transform from %s to %s with error: %s\n", msg_in.transforms[i].child_frame_id.c_str(), msg_in.transforms[i].header.frame_id.c_str(), temp.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user