dot_bt.cpp
Go to the documentation of this file.
00001 /* Copyright (C) 2017 Iason Sarantopoulos - All Rights Reserved
00002  *
00003  * Permission is hereby granted, free of charge, to any person obtaining a
00004  * copy of this software and associated documentation files (the "Software"),
00005  * to deal in the Software without restriction, including without limitation
00006  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00007  * and/or sell copies of the Software, and to permit persons to whom the
00008  * Software is furnished to do so, subject to the following conditions: The
00009  * above copyright notice and this permission notice shall be included in all
00010  * copies or substantial portions of the Software.
00011  *
00012  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00013  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00014  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00015  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00016  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00017  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00018  * DEALINGS IN THE SOFTWARE.
00019  */
00020 
00021 #include <dot_bt.h>
00022 #include <control_node.h>
00023 #include <std_msgs/String.h>
00024 #include <cctype>
00025 #include <algorithm>
00026 
00027 namespace BT
00028 {
00029 DotBt::DotBt(TreeNode* root, const std::string& topic, double ros_rate, bool left_right, bool multiple_parents) :
00030   root_(root),
00031   topic_(topic),
00032   loop_rate_(ros_rate),
00033   left_right_(left_right),
00034   multiple_parents_(multiple_parents)
00035 {
00036   dotbt_publisher_ = n_.advertise<std_msgs::String>(topic_, 1);
00037 
00038   ROS_INFO_STREAM("Visualization: Start publishing the tree in topic: "
00039       << topic_ << " with rate: " << ros_rate << " Hz.");
00040 }
00041 
00042 DotBt::~DotBt() {}
00043 
00044 std::string DotBt::defineNodeDot(TreeNode* node, const std::string& alias)
00045 {
00046   std::string output = alias + " ";
00047 
00048   // Find the type of the node and its shape and symbol (label).
00049   switch (node->DrawType())
00050   {
00051     case SELECTORSTAR:
00052       output += "[label=\"*\n?\" penwidth=\"2\"  shape=\"box\"";
00053       break;
00054     case BT::SEQUENCESTAR:
00055       output += "[label=\"*\n-->\" penwidth=\"2\"  shape=\"box\"";
00056       break;
00057     case BT::SELECTOR:
00058       output += "[label=\"?\" penwidth=\"2\"  shape=\"box\"";
00059       break;
00060     case BT::SEQUENCE:
00061       output += "[label=\"-->\" penwidth=\"2\"  shape=\"box\"";
00062       break;
00063     case BT::PARALLEL:
00064       output += "[label=\"-->\n-->\" penwidth=\"2\"  shape=\"box\"";
00065       break;
00066     case BT::DECORATOR:
00067       output += "[label=\"D\" penwidth=\"2\" shape=\"diamond\"";
00068       break;
00069     case BT::ACTION:
00070       output += "[label=\"" + node->get_name() + "\" penwidth=\"2\" shape=\"box\" fillcolor=\"palegreen\" style=\"filled\"";
00071       break;
00072     case BT::CONDITION:
00073       output += "[label=\"" + node->get_name() + "\" penwidth=\"2\" shape=\"ellipse\" fillcolor=\"khaki1\" style=\"filled\"";
00074       break;
00075     default:
00076       break;
00077   }
00078 
00079   // Get the current status of the node for the coloring.
00080   switch (node->get_color_status())
00081   {
00082     case BT::RUNNING:
00083       output += " color=\"black\" ];";
00084       break;
00085     case BT::SUCCESS:
00086       output += " color=\"green\" ];";
00087       break;
00088     case BT::FAILURE:
00089       output += " color=\"red\" ];";
00090       break;
00091     case BT::IDLE:
00092       output += " color=\"gray88\" ];";
00093       break;
00094     case BT::HALTED:
00095       output += " color=\"orange\" ];";
00096       break;
00097     default:
00098       output += " color=\"gray88\" ];";
00099       break;
00100   }
00101 
00102   return output;
00103 }
00104 
00105 void DotBt::produceDot(TreeNode* node, TreeNode* parent, const std::string& parent_alias)
00106 {
00107   // If this node is the root of the tree initialize the directed graph
00108   if (parent == NULL)
00109   {
00110     dot_file_ = "graph behavior_tree {\n";
00111     if (left_right_)
00112     {
00113       dot_file_ += "rankdir=LR;\n";
00114     }
00115 
00116     if (!multiple_parents_)
00117     {
00118       aliases_.clear();
00119     }
00120   }
00121 
00122   // Create an alias for naming the DOT object.
00123   std::string alias = getAlias(node->get_name());
00124 
00125   // Search if this alias has . In this case change the alias in order to use a
00126   // different visualization instance for this case.
00127 
00128 
00129   if (std::find(aliases_.begin(), aliases_.end(), alias) != aliases_.end())
00130   {
00131     alias += std::to_string(multiple_alias_solver_++);
00132   }
00133     aliases_.push_back(alias);
00134 
00135 
00136   // Add the definition of this node
00137   dot_file_ += defineNodeDot(node, alias) + "\n";
00138 
00139   // If the node has a parent, add it as a child of its parent.
00140   if (parent != NULL)
00141   {
00142     dot_file_ += parent_alias + " -- " + alias + ";\n";
00143   }
00144 
00145   // If this node has children run recursively for each child.
00146   BT::ControlNode* n = dynamic_cast<BT::ControlNode*> (node);
00147   if (n != NULL)
00148   {
00149     std::vector<TreeNode *> children = n->GetChildren();
00150     for (unsigned int i = 0; i < children.size(); i++)
00151     {
00152 
00153 //        if (children[i]->has_alias())
00154 //        {
00155 //            // cheking if I need to halt the child (has alias)
00156 //            for (unsigned int k=0; k < i; k++)
00157 //            {
00158 //                if (children[k] == children[i] && children[k]->get_status() == BT::HALTED )
00159 //                {
00160 //                }
00161 //                else
00162 //                {
00163 //                    color_child = false;
00164 //                    break;
00165 //                }
00166 //            }
00167 //        }
00168 
00169 
00170 
00171       produceDot(children.at(i), node, alias);
00172     }
00173   }
00174 
00175   // In case every recursive calls returns to the root call, close the file.
00176   if (parent == NULL)
00177   {
00178     dot_file_ += "\n}";
00179   }
00180 }
00181 
00182 std::string DotBt::getAlias(const std::string &name)
00183 {
00184   // Transform name to lower case
00185   std::string out = boost::to_lower_copy<std::string>(name);
00186 
00187   // If first character is digit add a letter at the beginning
00188   // in order to avoid weird aliases
00189   if (std::isdigit(out.at(0)))
00190   {
00191     out.insert(0, "a");
00192   }
00193 
00194 
00195   // Replace spaces and dashes with underscore
00196   for (std::string::iterator it = out.begin(); it != out.end(); ++it)
00197   {
00198     if (*it == ' ' || *it == '-')
00199     {
00200       *it = '_';
00201     }
00202   }
00203   return out;
00204 }
00205 
00206 std::string DotBt::getDotFile()
00207 {
00208   return dot_file_;
00209 }
00210 
00211 void DotBt::publish()
00212 {
00213   std_msgs::String msg;
00214 
00215   // Start the loop for publishing the tree
00216   while (ros::ok())
00217   {
00218     produceDot(root_);
00219     msg.data = dot_file_;
00220     dotbt_publisher_.publish(msg);
00221     ros::spinOnce();
00222     loop_rate_.sleep();
00223   }
00224 }
00225 }  // namespace BT


behavior_tree_core
Author(s): Michele Colledanchise
autogenerated on Sun Sep 10 2017 02:31:49