hwi_switch_test.cpp
Go to the documentation of this file.
00001 
00002 // Copyright (C) 2015, Fraunhofer IPA
00003 //
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are met:
00006 //   * Redistributions of source code must retain the above copyright notice,
00007 //     this list of conditions and the following disclaimer.
00008 //   * Redistributions in binary form must reproduce the above copyright
00009 //     notice, this list of conditions and the following disclaimer in the
00010 //     documentation and/or other materials provided with the distribution.
00011 //   * Neither the name of Fraunhofer IPA nor the names of its
00012 //     contributors may be used to endorse or promote products derived from
00013 //     this software without specific prior written permission.
00014 //
00015 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00016 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00019 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00024 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00025 // POSSIBILITY OF SUCH DAMAGE.
00027 
00029 
00030 #include <gtest/gtest.h>
00031 
00032 #include <map>
00033 #include <set>
00034 #include <string>
00035 #include <algorithm>
00036 #include <iterator>
00037 
00038 #include <controller_manager/controller_manager.h>
00039 #include <hardware_interface/robot_hw.h>
00040 #include <hardware_interface/joint_command_interface.h>
00041 
00042 namespace hardware_interface {
00043 bool operator<(hardware_interface::ControllerInfo const& i1, hardware_interface::ControllerInfo const& i2)
00044 {
00045     return i1.name < i2.name;
00046 }
00047 }
00048 template<typename T> T intersect(const T& v1, const T &v2)
00049 {
00050 
00051     std::vector<typename T::value_type> sorted1(v1.begin(), v1.end()), sorted2(v2.begin(), v2.end());
00052     T res;
00053 
00054     std::sort(sorted1.begin(), sorted1.end());
00055     std::sort(sorted2.begin(), sorted2.end());
00056 
00057     std::set_intersection(sorted1.begin(), sorted1.end(), sorted2.begin(), sorted2.end(), std::back_inserter(res));
00058     return res;
00059 }
00060 
00061 class SwitchBot : public hardware_interface::RobotHW
00062 {
00063     hardware_interface::JointStateInterface jsi_;
00064     hardware_interface::PositionJointInterface pji_;
00065     hardware_interface::VelocityJointInterface vji_;
00066     hardware_interface::EffortJointInterface eji_;
00067 
00068     class Joint
00069     {
00070         double dummy_;
00071         std::set<std::string> interfaces_;
00072         std::string current_;
00073         hardware_interface::JointStateHandle jsh_;
00074     public:
00075         Joint(const std::string &n, hardware_interface::JointStateInterface &iface): jsh_(n, &dummy_, &dummy_, &dummy_)
00076         {
00077             iface.registerHandle(jsh_);
00078         }
00079 
00080         template<typename Interface> void registerHandle(Interface &iface, bool can_switch)
00081         {
00082             if(can_switch) interfaces_.insert(hardware_interface::internal::demangledTypeName<Interface>() );
00083             iface.registerHandle(typename Interface::ResourceHandleType(jsh_, &dummy_));
00084         }
00085         bool canSwitch(const std::string &n) const
00086         {
00087             if(interfaces_.find(n) == interfaces_.end()) return false;
00088             return n >= current_;
00089         }
00090         void doSwitch(const std::string &n)
00091         {
00092             current_ = n;
00093         }
00094     };
00095 
00096     typedef boost::shared_ptr<Joint> JointSharedPtr;
00097 
00098     std::map<std::string,  JointSharedPtr> joints_;
00099 
00100     JointSharedPtr makeJoint(const std::string & name)
00101     {
00102         JointSharedPtr j(new Joint(name, jsi_));
00103         joints_.insert(std::make_pair(name, j));
00104         return j;
00105     }
00106 
00107     std::vector<std::string> started_;
00108     std::vector<std::string> stopped_;
00109 public:
00110     SwitchBot()
00111     {
00112         JointSharedPtr j;
00113 
00114         j = makeJoint("j_pv");
00115 
00116         j->registerHandle(pji_, true);
00117         j->registerHandle(vji_, true);
00118         j->registerHandle(eji_, false);
00119 
00120         j = makeJoint("j_pe");
00121         j->registerHandle(pji_, true);
00122         j->registerHandle(vji_, false);
00123         j->registerHandle(eji_, true);
00124 
00125         j = makeJoint("j_ve");
00126         j->registerHandle(pji_, false);
00127         j->registerHandle(vji_, true);
00128         j->registerHandle(eji_, true);
00129 
00130         registerInterface(&pji_);
00131         registerInterface(&vji_);
00132         registerInterface(&eji_);
00133 
00134     }
00135 
00136     virtual bool canSwitch(const std::list<hardware_interface::ControllerInfo> &start_list, const std::list<hardware_interface::ControllerInfo> &stop_list) const
00137     {
00138 
00139         if(!RobotHW::canSwitch(start_list, stop_list))
00140         {
00141             ROS_ERROR("Something is wrong with RobotHW");
00142             return false;
00143         }
00144 
00145         if(!intersect(start_list, stop_list).empty())
00146         {
00147             ROS_ERROR_STREAM("start_list and stop_list intersect");
00148             return false;
00149         }
00150 
00151         bool j_pe_e = false;
00152         bool j_ve_v = false;
00153 
00154         for(std::list<hardware_interface::ControllerInfo>::const_iterator it = start_list.begin(); it != start_list.end(); ++it)
00155         {
00156             for (std::set<std::string>::const_iterator res_it = it->resources.begin(); res_it != it->resources.end(); ++res_it)
00157             {
00158 
00159                 // special check
00160                 if(it->hardware_interface == "hardware_interface::EffortJointInterface" && *res_it == "j_pe") j_pe_e = true;
00161                 else if(it->hardware_interface == "hardware_interface::VelocityJointInterface" && *res_it == "j_ve") j_ve_v = true;
00162 
00163                 // per joint check
00164                 try
00165                 {
00166                     if(!joints_.at(*res_it)->canSwitch(it->hardware_interface))
00167                     {
00168                         ROS_ERROR_STREAM("Cannot switch " << *res_it << " to " << it->hardware_interface);
00169                         return false;
00170                     }
00171                 }
00172                 catch(...)
00173                 {
00174                     ROS_FATAL("This should never happen!");
00175                     return false;
00176                 }
00177             }
00178         }
00179         return !(j_pe_e && j_ve_v); // check inter-joint hardware interface conflict
00180     }
00181     virtual void doSwitch(const std::list<hardware_interface::ControllerInfo> &start_list, const std::list<hardware_interface::ControllerInfo> &stop_list)
00182     {
00183         RobotHW::doSwitch(start_list, stop_list); // check if member is defined
00184 
00185         std::map<std::string, std::string> switches;
00186         for(std::list<hardware_interface::ControllerInfo>::const_iterator it = stop_list.begin(); it != stop_list.end(); ++it)
00187         {
00188             started_.erase(std::remove(started_.begin(), started_.end(), it->name), started_.end());
00189             stopped_.push_back(it->name);
00190             for (std::set<std::string>::const_iterator res_it = it->resources.begin(); res_it != it->resources.end(); ++res_it)
00191             {
00192                 switches[*res_it] = "";
00193             }
00194         }
00195         for(std::list<hardware_interface::ControllerInfo>::const_iterator it = start_list.begin(); it != start_list.end(); ++it)
00196         {
00197 
00198             stopped_.erase(std::remove(stopped_.begin(), stopped_.end(), it->name), stopped_.end());
00199             started_.push_back(it->name);
00200             for (std::set<std::string>::const_iterator res_it = it->resources.begin(); res_it != it->resources.end(); ++res_it)
00201             {
00202                 switches[*res_it] = it->hardware_interface;
00203             }
00204         }
00205         for(std::map<std::string, std::string>::iterator it = switches.begin(); it != switches.end(); ++it)
00206         {
00207             joints_[it->first]->doSwitch(it->second);
00208         }
00209     }
00210     bool checkUnqiue() const
00211     {
00212         return intersect(started_, stopped_).empty();
00213     }
00214     bool checkNotRunning() const
00215     {
00216         return started_.empty();
00217     }
00218 };
00219 
00220 
00221 class DummyControllerLoader: public controller_manager::ControllerLoaderInterface
00222 {
00223     class DummyController : public controller_interface::ControllerBase
00224     {
00225         const std::string type_name;
00226     public:
00227         DummyController(const std::string &name) : type_name(name) {}
00228         virtual void update(const ros::Time& /*time*/, const ros::Duration& /*period*/) {}
00229         virtual bool initRequest(hardware_interface::RobotHW* /*hw*/,
00230                                  ros::NodeHandle& /*root_nh*/,
00231                                  ros::NodeHandle &controller_nh,
00232                                  std::set<std::string>& claimed_resources)
00233         {
00234             std::vector<std::string> joints;
00235             if(!controller_nh.getParam("joints", joints))
00236             {
00237                 ROS_ERROR("Could not parse joint names");
00238                 return false;
00239             }
00240             claimed_resources.insert(joints.begin(), joints.end());
00241             state_ = INITIALIZED;
00242             return true;
00243         }
00244         virtual std::string getHardwareInterfaceType() const
00245         {
00246             return type_name;
00247         }
00248     };
00249 
00250     std::map<std::string, std::string> classes;
00251     void add(const std::string type)
00252     {
00253         classes.insert(std::make_pair("Dummy" + type + "Controller", "hardware_interface::" + type));
00254     }
00255 public:
00256     DummyControllerLoader() : ControllerLoaderInterface("controller_interface::ControllerBase")
00257     {
00258         add("EffortJointInterface");
00259         add("PositionJointInterface");
00260         add("VelocityJointInterface");
00261     }
00262     virtual controller_interface::ControllerBaseSharedPtr createInstance(const std::string& lookup_name)
00263     {
00264         return controller_interface::ControllerBaseSharedPtr(new DummyController(classes.at(lookup_name)));
00265     }
00266     virtual std::vector<std::string> getDeclaredClasses()
00267     {
00268         std::vector<std::string> v;
00269         for(std::map<std::string, std::string>::iterator it = classes.begin(); it != classes.end(); ++it)
00270         {
00271             v.push_back(it->first);
00272         }
00273         return v;
00274     }
00275     virtual void reload() {}
00276 };
00277 
00278 void update(controller_manager::ControllerManager &cm, const ros::TimerEvent& e)
00279 {
00280     cm.update(e.current_real, e.current_real - e.last_real);
00281 }
00282 
00283 class GuardROS
00284 {
00285 public:
00286     ~GuardROS()
00287     {
00288         ros::shutdown();
00289         ros::waitForShutdown();
00290     }
00291 };
00292 
00293 TEST(SwitchInterfacesTest, SwitchInterfaces)
00294 {
00295     GuardROS guard;
00296 
00297     SwitchBot bot;
00298     ros::NodeHandle nh;
00299 
00300     controller_manager::ControllerManager cm(&bot);
00301 
00302     cm.registerControllerLoader(boost::make_shared<DummyControllerLoader>());
00303 
00304     ros::Timer timer = nh.createTimer(ros::Duration(0.01), boost::bind(update, boost::ref(cm), _1));
00305 
00306     ASSERT_TRUE(cm.loadController("group_pos"));
00307     ASSERT_TRUE(cm.loadController("another_group_pos"));
00308     ASSERT_TRUE(cm.loadController("group_vel"));
00309     ASSERT_TRUE(cm.loadController("group_eff"));
00310     ASSERT_TRUE(cm.loadController("single_pos"));
00311     ASSERT_TRUE(cm.loadController("single_eff"));
00312     ASSERT_TRUE(cm.loadController("invalid_group_pos"));
00313     ASSERT_FALSE(cm.loadController("totally_random_name"));
00314 
00315     {   // test hardware interface conflict
00316         std::vector<std::string> start, stop;
00317         start.push_back("invalid_group_pos");
00318         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00319     }
00320     {   // test resource conflict
00321         std::vector<std::string> start, stop;
00322         start.push_back("group_pos");
00323         start.push_back("group_vel");
00324         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00325     }
00326     {   // test pos group
00327         std::vector<std::string> start, stop;
00328         start.push_back("group_pos");
00329         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00330         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00331     }
00332     {   // test same hardware interface switch
00333         std::vector<std::string> start, stop, next_start;
00334         start.push_back("group_pos");
00335         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00336 
00337         next_start.push_back("group_pos");
00338         ASSERT_TRUE(cm.switchController(next_start, start, controller_manager_msgs::SwitchControllerRequest::STRICT));
00339 
00340         ASSERT_TRUE(cm.switchController(stop, next_start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00341     }
00342     {   // test same hardware interface switch
00343         std::vector<std::string> start, stop, next_start;
00344         start.push_back("group_pos");
00345         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00346 
00347         next_start.push_back("another_group_pos");
00348         ASSERT_TRUE(cm.switchController(next_start, start, controller_manager_msgs::SwitchControllerRequest::STRICT));
00349 
00350         ASSERT_TRUE(cm.switchController(stop, next_start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00351     }
00352     {   // test vel group
00353         std::vector<std::string> start, stop;
00354         start.push_back("group_vel");
00355         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00356         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00357     }
00358     {   // test eff group
00359         std::vector<std::string> start, stop;
00360         start.push_back("group_eff");
00361         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00362         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00363     }
00364 
00365     {   // test direct hardware interface upgrades (okay) and downgrades (conflict)
00366         std::vector<std::string> start, stop, next_start;
00367         start.push_back("group_eff");
00368         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00369 
00370         next_start.push_back("group_vel");
00371         ASSERT_TRUE(cm.switchController(next_start, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // upgrade
00372 
00373         ASSERT_FALSE(cm.switchController(start, next_start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // downgrade
00374 
00375         ASSERT_TRUE(cm.switchController(stop, next_start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00376     }
00377 
00378     {   // test single pos
00379         std::vector<std::string> start, stop;
00380         start.push_back("single_pos");
00381         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00382         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00383     }
00384     {   // test single eff
00385         std::vector<std::string> start, stop;
00386         start.push_back("single_pos");
00387         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00388         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00389     }
00390     {   // test single pos + group_eff (resource conflict)
00391         std::vector<std::string> start, stop;
00392         start.push_back("single_pos");
00393         start.push_back("group_eff");
00394         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00395     }
00396     {   // test single pos + group_eff (hardware interface conflict)
00397         std::vector<std::string> start, stop;
00398         start.push_back("single_eff");
00399         start.push_back("group_vel");
00400         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00401     }
00402     {   // test single pos + group_vel
00403         std::vector<std::string> start, stop;
00404         start.push_back("single_pos");
00405         start.push_back("group_vel");
00406         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00407         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00408     }
00409     {   // test single pos + group_vel + totally_random_name
00410         std::vector<std::string> start, stop;
00411         start.push_back("single_pos");
00412         start.push_back("group_vel");
00413         start.push_back("totally_random_name");
00414         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00415         ASSERT_FALSE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT));
00416 
00417         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::BEST_EFFORT));
00418         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::BEST_EFFORT)); // clean-up
00419     }
00420     {   // test restart
00421         std::vector<std::string> start, stop;
00422         start.push_back("single_pos");
00423         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00424 
00425         ASSERT_TRUE(cm.switchController(start, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // restart
00426         ASSERT_TRUE(bot.checkUnqiue());
00427 
00428         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT));  // clean-up
00429     }
00430     {   // test stop for controller that is not running
00431         std::vector<std::string> start, stop;
00432         stop.push_back("single_pos");
00433         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00434         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::BEST_EFFORT));
00435     }
00436     {   // test stop for controller that is not running
00437         std::vector<std::string> start, stop;
00438         start.push_back("single_pos");
00439         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00440         ASSERT_FALSE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::STRICT));
00441         ASSERT_TRUE(cm.switchController(start, stop, controller_manager_msgs::SwitchControllerRequest::BEST_EFFORT));
00442         ASSERT_TRUE(cm.switchController(stop, start, controller_manager_msgs::SwitchControllerRequest::STRICT)); // clean-up
00443     }
00444     ASSERT_TRUE(bot.checkNotRunning());
00445 }
00446 
00447 int main(int argc, char **argv)
00448 {
00449     testing::InitGoogleTest(&argc, argv);
00450     ros::init(argc, argv, "controller_manager_switch_test");
00451 
00452     ros::AsyncSpinner spinner(1);
00453     spinner.start();
00454     int ret = RUN_ALL_TESTS();
00455     return ret;
00456 }


controller_manager
Author(s): Wim Meeussen, Mathias Lüdtke
autogenerated on Sat Jun 8 2019 20:09:23