support publishing of partial trees. Ticket #4464

This commit is contained in:
Wim Meeussen 2011-03-23 12:09:14 -07:00
parent f9c4811229
commit 0cac9e781a
4 changed files with 154 additions and 120 deletions

View File

@ -62,11 +62,14 @@ public:
private: private:
void callbackJointState(const JointStateConstPtr& state); void callbackJointState(const JointStateConstPtr& state);
void callbackFixedJoint(const ros::TimerEvent& e);
NodeHandle n_, n_tilde_; Duration publish_interval_;
Rate publish_rate_;
robot_state_publisher::RobotStatePublisher state_publisher_; robot_state_publisher::RobotStatePublisher state_publisher_;
Subscriber joint_state_sub_; Subscriber joint_state_sub_;
ros::Timer timer_;
ros::Time last_publish_time_;
}; };
} }

View File

@ -41,10 +41,23 @@
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <tf/tf.h> #include <tf/tf.h>
#include <tf/transform_broadcaster.h> #include <tf/transform_broadcaster.h>
#include "robot_state_publisher/treefksolverposfull_recursive.hpp" #include <kdl/frames.hpp>
#include <kdl/segment.hpp>
#include <kdl/tree.hpp>
namespace robot_state_publisher{ namespace robot_state_publisher{
class SegmentPair
{
public:
SegmentPair(const KDL::Segment& p_segment, const std::string& p_root, const std::string& p_tip):
segment(p_segment), root(p_root), tip(p_tip){}
KDL::Segment segment;
std::string root, tip;
};
class RobotStatePublisher class RobotStatePublisher
{ {
public: public:
@ -62,21 +75,14 @@ public:
* returns true on success; return false when the robot model is empty or not all the joints in the robot model are specified in the joint map. * returns true on success; return false when the robot model is empty or not all the joints in the robot model are specified in the joint map.
*/ */
bool publishTransforms(const std::map<std::string, double>& joint_positions, const ros::Time& time); bool publishTransforms(const std::map<std::string, double>& joint_positions, const ros::Time& time);
void publishFixedTransforms();
private: private:
ros::Publisher tf_publisher_; void addChildren(const KDL::SegmentMap::const_iterator segment);
bool flatten_tree_;
KDL::Tree tree_;
boost::scoped_ptr<KDL::TreeFkSolverPosFull_recursive> solver_;
std::string root_;
std::vector<tf::StampedTransform> transforms_;
tf::TransformBroadcaster tf_broadcaster_;
class empty_tree_exception: public std::exception{
virtual const char* what() const throw(){
return "Tree is empty";}
} empty_tree_ex;
std::map<std::string, SegmentPair> segments_, segments_fixed_;
tf::TransformBroadcaster tf_broadcaster_, tf_broadcaster_fixed_;
}; };

View File

@ -48,25 +48,24 @@ using namespace robot_state_publisher;
JointStateListener::JointStateListener(const KDL::Tree& tree) JointStateListener::JointStateListener(const KDL::Tree& tree)
: n_tilde_("~"), publish_rate_(0.0), state_publisher_(tree) : state_publisher_(tree)
{ {
ros::NodeHandle n_tilde("~");
ros::NodeHandle n;
// set publish frequency // set publish frequency
double publish_freq; double publish_freq;
n_tilde_.param("publish_frequency", publish_freq, 50.0); n_tilde.param("publish_frequency", publish_freq, 50.0);
publish_rate_ = Rate(publish_freq); publish_interval_ = ros::Duration(1.0/max(publish_freq,1.0));
// subscribe to joint state
joint_state_sub_ = n.subscribe("joint_states", 1, &JointStateListener::callbackJointState, this);
// trigger to publish fixed joints
last_publish_time_ = ros::Time();
timer_ = n_tilde.createTimer(publish_interval_, &JointStateListener::callbackFixedJoint, this);
if (tree.getNrOfJoints() == 0){
boost::shared_ptr<sensor_msgs::JointState> empty_state(new sensor_msgs::JointState);
while (ros::ok()){
empty_state->header.stamp = ros::Time::now();
this->callbackJointState(empty_state);
publish_rate_.sleep();
}
}
else{
// subscribe to mechanism state
joint_state_sub_ = n_.subscribe("joint_states", 1, &JointStateListener::callbackJointState, this);
}
}; };
@ -74,6 +73,11 @@ JointStateListener::~JointStateListener()
{}; {};
void JointStateListener::callbackFixedJoint(const ros::TimerEvent& e)
{
state_publisher_.publishFixedTransforms();
}
void JointStateListener::callbackJointState(const JointStateConstPtr& state) void JointStateListener::callbackJointState(const JointStateConstPtr& state)
{ {
if (state->name.size() != state->position.size()){ if (state->name.size() != state->position.size()){
@ -81,12 +85,15 @@ void JointStateListener::callbackJointState(const JointStateConstPtr& state)
return; return;
} }
// check if we need to publish
if (state->header.stamp >= last_publish_time_ + publish_interval_){
// get joint positions from state message // get joint positions from state message
map<string, double> joint_positions; map<string, double> joint_positions;
for (unsigned int i=0; i<state->name.size(); i++) for (unsigned int i=0; i<state->name.size(); i++)
joint_positions.insert(make_pair(state->name[i], state->position[i])); joint_positions.insert(make_pair(state->name[i], state->position[i]));
state_publisher_.publishTransforms(joint_positions, state->header.stamp); state_publisher_.publishTransforms(joint_positions, state->header.stamp);
publish_rate_.sleep(); last_publish_time_ = state->header.stamp;
}
} }
@ -109,14 +116,8 @@ int main(int argc, char** argv)
return -1; return -1;
} }
if (tree.getNrOfSegments() == 0){
ROS_WARN("Robot state publisher got an empty tree and cannot publish any state to tf");
ros::spin();
}
else{
JointStateListener state_publisher(tree); JointStateListener state_publisher(tree);
ros::spin(); ros::spin();
}
return 0; return 0;
} }

View File

@ -40,59 +40,83 @@
using namespace std; using namespace std;
using namespace ros; using namespace ros;
using namespace KDL;
namespace robot_state_publisher{ namespace robot_state_publisher{
RobotStatePublisher::RobotStatePublisher(const Tree& tree) RobotStatePublisher::RobotStatePublisher(const KDL::Tree& tree)
:tree_(tree)
{ {
// build tree solver // walk the tree and add segments to segments_
solver_.reset(new TreeFkSolverPosFull_recursive(tree_)); addChildren(tree.getRootSegment());
// get parameter to flatter tree or not
ros::NodeHandle n_private("~");
n_private.param("flatten_tree", flatten_tree_, false);
// advertise tf message
NodeHandle n;
tf_publisher_ = n.advertise<tf::tfMessage>("/tf", 5);
// get the root segment of the tree
SegmentMap::const_iterator root = tree.getRootSegment();
root_ = root->first;
} }
// add children to correct maps
void RobotStatePublisher::addChildren(const KDL::SegmentMap::const_iterator segment)
{
const std::string& root = segment->second.segment.getName();
const std::vector<KDL::SegmentMap::const_iterator>& children = segment->second.children;
for (unsigned int i=0; i<children.size(); i++){
const KDL::Segment& child = children[i]->second.segment;
SegmentPair s(children[i]->second.segment, root, child.getName());
if (child.getJoint().getType() == KDL::Joint::None){
segments_fixed_.insert(make_pair(child.getJoint().getName(), s));
ROS_INFO("Adding fixed segment from %s to %s", root.c_str(), child.getName().c_str());
}
else{
segments_.insert(make_pair(child.getJoint().getName(), s));
ROS_INFO("Adding moving segment from %s to %s", root.c_str(), child.getName().c_str());
}
addChildren(children[i]);
}
}
// publish moving transforms
bool RobotStatePublisher::publishTransforms(const map<string, double>& joint_positions, const Time& time) bool RobotStatePublisher::publishTransforms(const map<string, double>& joint_positions, const Time& time)
{ {
// calculate transforms std::vector<tf::StampedTransform> tf_transforms;
map<string, tf::Stamped<Frame> > link_poses;
solver_->JntToCart(joint_positions, link_poses, flatten_tree_);
if (link_poses.empty()){ tf::StampedTransform tf_transform;
ROS_ERROR("Could not compute link poses. The tree or the state is invalid."); tf_transform.stamp_ = time;
return false;
// loop over all joints
for (map<string, double>::const_iterator jnt=joint_positions.begin(); jnt != joint_positions.end(); jnt++){
std::map<std::string, SegmentPair>::const_iterator seg = segments_.find(jnt->first);
if (seg != segments_.end()){
tf::TransformKDLToTF(seg->second.segment.pose(jnt->second), tf_transform);
tf_transform.frame_id_ = seg->second.root;
tf_transform.child_frame_id_ = seg->second.tip;
tf_transforms.push_back(tf_transform);
} }
transforms_.resize(link_poses.size());
unsigned int i = 0;
tf::Transform tf_frame;
for (map<string, tf::Stamped<Frame> >::const_iterator f=link_poses.begin(); f!=link_poses.end(); f++){
tf::TransformKDLToTF(f->second, transforms_[i]);
transforms_[i].stamp_ = time;
transforms_[i].frame_id_ = f->second.frame_id_;
transforms_[i].child_frame_id_ = f->first;
i++;
} }
tf_broadcaster_.sendTransform(transforms_); tf_broadcaster_.sendTransform(tf_transforms);
return true; return true;
} }
// publish fixed transforms
void RobotStatePublisher::publishFixedTransforms()
{
std::vector<tf::StampedTransform> tf_transforms;
tf::StampedTransform tf_transform;
tf_transform.stamp_ = ros::Time::now()+ros::Duration(0.5); // future publish by 0.5 seconds
// loop over all fixed segments
for (map<string, SegmentPair>::const_iterator seg=segments_fixed_.begin(); seg != segments_fixed_.end(); seg++){
tf::TransformKDLToTF(seg->second.segment.pose(0), tf_transform);
tf_transform.frame_id_ = seg->second.root;
tf_transform.child_frame_id_ = seg->second.tip;
tf_transforms.push_back(tf_transform);
}
tf_broadcaster_fixed_.sendTransform(tf_transforms);
}
} }