tf_remapper_node.cpp
Go to the documentation of this file.
00001 #include <tf_remapper_cpp/tf_remapper_node.h>
00002 #include <set>
00003 
00004 tf_remapper_cpp::TfRemapperNode::TfRemapperNode() : privateNodeHandle("~")
00005 {
00006     this->oldTfTopic = this->privateNodeHandle.param<std::string>("old_tf_topic_name", "/tf_old");
00007     this->remappedTfTopic = this->privateNodeHandle.param<std::string>("new_tf_topic_name", "/tf");
00008 
00009     if (this->privateNodeHandle.hasParam("static_tf"))
00010         this->staticTf = this->privateNodeHandle.param<bool>("static_tf", false);
00011     else
00012         // Autodetect if the parameter is not set
00013         this->staticTf = this->remappedTfTopic == "tf_static" || this->remappedTfTopic == "/tf_static";
00014 
00015     // Parse the 'mappings' parameter, which should be an array of dicts, e.g. [{"old": "b", "new": "d"}]
00016     XmlRpc::XmlRpcValue mappingsParam;
00017     const bool hasMappingsParam = this->privateNodeHandle.getParam("mappings", mappingsParam);
00018     if (!hasMappingsParam) {
00019         mappingsParam.setSize(0); // makes it an empty array
00020         ROS_WARN("The 'mappings' parameter to tf_remap is missing");
00021     }
00022 
00023     const bool bidirectional = this->privateNodeHandle.param<bool>("is_bidirectional", false);
00024 
00025     this->tfRemapper = TfRemapper(mappingsParam);
00026     if (bidirectional)
00027         this->reverseTfRemapper = TfRemapper(mappingsParam, true);
00028 
00029     if (!tfRemapper.getMappings().empty()) {
00030         ROS_INFO_STREAM("Applying the following mappings" << (bidirectional ? " bidirectionally" : "") <<
00031                         " to incoming tf frame ids:");
00032         for (TfRemapper::MappingsType::const_iterator it = tfRemapper.getMappings().begin();
00033                 it != tfRemapper.getMappings().end(); ++it) {
00034             ROS_INFO_STREAM("* " << it->first << " " << (bidirectional && !it->second.empty() ? "<" : "") << "-> " <<
00035                                     (it->second.empty() ? "DELETE" : it->second));
00036         }
00037         if (bidirectional) {
00038             for (TfRemapper::MappingsType::const_iterator it = reverseTfRemapper.getMappings().begin();
00039                     it != reverseTfRemapper.getMappings().end(); ++it) {
00040                 if (it->second.empty())
00041                     ROS_INFO_STREAM("* DELETE <- " << it->first);
00042             }
00043         }
00044     } else {
00045         ROS_WARN("No mappings defined.");
00046     }
00047 
00048     ROS_INFO_STREAM("Old TF topic: " << this->oldTfTopic);
00049     ROS_INFO_STREAM("Remapped TF topic: " << this->remappedTfTopic);
00050     if (this->staticTf)
00051         ROS_INFO("Running in static TF mode (caching all TFs, latched publisher)");
00052 
00053     this->oldTfSubscriber = this->publicNodeHandle.subscribe(
00054             this->oldTfTopic, 100, &TfRemapperNode::oldTfCallback, this);
00055     this->remappedTfPublisher = this->publicNodeHandle.advertise<tf2_msgs::TFMessage>(
00056         this->remappedTfTopic, 100, this->staticTf);
00057 
00058     if (bidirectional) {
00059         this->remappedTfSubscriber = this->publicNodeHandle.subscribe(
00060                 this->remappedTfTopic, 100, &TfRemapperNode::remappedTfCallback, this);
00061         this->oldTfPublisher = this->publicNodeHandle.advertise<tf2_msgs::TFMessage>(
00062                 this->oldTfTopic, 100, this->staticTf);
00063     }
00064 }
00065 
00066 void tf_remapper_cpp::TfRemapperNode::oldTfCallback(const ros::MessageEvent<tf2_msgs::TFMessage const>& event) {
00067     // Prevent reacting to own messages from bidirectional mode
00068     const std::string& callerid = event.getPublisherName();
00069     if (callerid == ros::this_node::getName())
00070         return;
00071 
00072     tf2_msgs::TFMessage message = this->tfRemapper.doRemapping(*event.getConstMessage());
00073 
00074     // Since static TF can come from many latched publishers, and we are only a single publisher, we must gather all
00075     // the static TF messages in a cache and every time publish all of them.
00076     if (this->staticTf) {
00077         this->addToStaticTfCache(message, this->staticTfCache);
00078         this->remappedTfPublisher.publish(this->staticTfCache);
00079     } else {
00080         this->remappedTfPublisher.publish(message);
00081     }
00082 }
00083 
00084 void tf_remapper_cpp::TfRemapperNode::remappedTfCallback(const ros::MessageEvent<tf2_msgs::TFMessage const>& event) {
00085     // Prevent reacting to own messages from bidirectional mode
00086     const std::string& callerid = event.getPublisherName();
00087     if (callerid == ros::this_node::getName())
00088         return;
00089 
00090     tf2_msgs::TFMessage message = this->reverseTfRemapper.doRemapping(*event.getConstMessage());
00091 
00092     // Since static TF can come from many latched publishers, and we are only a single publisher, we must gather all
00093     // the static TF messages in a cache and every time publish all of them.
00094     if (this->staticTf) {
00095         this->addToStaticTfCache(message, this->reverseStaticTfCache);
00096         this->oldTfPublisher.publish(this->reverseStaticTfCache);
00097     } else {
00098         this->oldTfPublisher.publish(message);
00099     }
00100 }
00101 
00102 void tf_remapper_cpp::TfRemapperNode::addToStaticTfCache(
00103         const tf2_msgs::TFMessage& message, tf2_msgs::TFMessage& cache) const {
00104     // We do an inefficient O(N^2) search here, but there should not be that many static TFs that it would matter
00105     for (std::vector<geometry_msgs::TransformStamped>::const_iterator it = message.transforms.begin();
00106             it != message.transforms.end(); ++it) {
00107         bool found = false;
00108         for (std::vector<geometry_msgs::TransformStamped>::iterator cacheIt = cache.transforms.begin();
00109                 cacheIt != cache.transforms.end(); ++cacheIt) {
00110             if (it->child_frame_id == cacheIt->child_frame_id) {
00111                 found = true;
00112                 *cacheIt = *it;
00113                 break;
00114             }
00115         }
00116         if (!found)
00117             cache.transforms.push_back(*it);
00118     }
00119 }
00120 
00121 int main(int argc, char * argv[])
00122 {
00123     ros::init(argc, argv, "tf_remapper");
00124     tf_remapper_cpp::TfRemapperNode remapper;
00125     ros::spin();
00126     return 0;
00127 }


tf_remapper_cpp
Author(s): Martin Pecka
autogenerated on Tue Mar 19 2019 09:29:23