cob_light.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 
00018 // standard includes
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <sstream>
00022 #include <math.h>
00023 #include <signal.h>
00024 
00025 // ros includes
00026 #include <ros/ros.h>
00027 #include <actionlib/server/simple_action_server.h>
00028 #include <diagnostic_msgs/DiagnosticArray.h>
00029 #include <ros/xmlrpc_manager.h>
00030 
00031 // ros message includes
00032 #include <std_msgs/ColorRGBA.h>
00033 #include <std_msgs/UInt64.h>
00034 #include <visualization_msgs/Marker.h>
00035 #include <cob_light/ColorRGBAArray.h>
00036 #include <cob_light/LightMode.h>
00037 #include <cob_light/LightModes.h>
00038 #include <cob_light/SetLightMode.h>
00039 #include <cob_light/SetLightModeAction.h>
00040 #include <cob_light/SetLightModeActionGoal.h>
00041 #include <cob_light/SetLightModeActionResult.h>
00042 #include <cob_light/StopLightMode.h>
00043 
00044 // serial connection includes
00045 #include <serialIO.h>
00046 
00047 // additional includes
00048 #include <colorUtils.h>
00049 #include <modeExecutor.h>
00050 #include <colorO.h>
00051 #include <colorOSim.h>
00052 #include <ms35.h>
00053 #include <stageprofi.h>
00054 
00055 sig_atomic_t volatile gShutdownRequest = 0;
00056 
00057 void sigIntHandler(int signal)
00058 {
00059   ::gShutdownRequest = 1;
00060 }
00061 
00062 void shutdownCallback(XmlRpc::XmlRpcValue& params, XmlRpc::XmlRpcValue& result)
00063 {
00064   int num_params = 0;
00065   if (params.getType() == XmlRpc::XmlRpcValue::TypeArray)
00066     num_params = params.size();
00067   if (num_params > 1)
00068   {
00069     std::string reason = params[1];
00070     ROS_WARN("Shutdown request received. Reason: [%s]", reason.c_str());
00071     ::gShutdownRequest = 1; // Set flag
00072   }
00073 
00074   result = ros::xmlrpc::responseInt(1, "", 0);
00075 }
00076 
00077 class LightControl
00078 {
00079 public:
00080   LightControl() :
00081     _invertMask(0), _topic_priority(0)
00082   {
00083   }
00084   bool init()
00085   {
00086     bool ret = true;
00087     bool invert_output;
00088     XmlRpc::XmlRpcValue param_list;
00089     std::string startup_mode;
00090     p_colorO = NULL;
00091     p_modeExecutor = NULL;
00092     //diagnostics
00093     _pubDiagnostic = _nh.advertise<diagnostic_msgs::DiagnosticArray>("/diagnostics", 1);
00094     _diagnostics_timer = _nh.createTimer(ros::Duration(1.0), &LightControl::publish_diagnostics_cb, this);
00095 
00096     diagnostic_msgs::DiagnosticStatus status;
00097     status.name = ros::this_node::getName();
00098 
00099     //Get Parameter from Parameter Server
00100     _nh = ros::NodeHandle("~");
00101     if(!_nh.hasParam("invert_output"))
00102       ROS_WARN("Parameter 'invert_output' is missing. Using default Value: false");
00103     _nh.param<bool>("invert_output", invert_output, false);
00104     _invertMask = (int)invert_output;
00105 
00106     if(!_nh.hasParam("devicedriver"))
00107       ROS_WARN("Parameter 'devicedriver' is missing. Using default Value: cob_ledboard");
00108     _nh.param<std::string>("devicedriver",_deviceDriver,"cob_ledboard");
00109 
00110     if(!_nh.hasParam("devicestring"))
00111       ROS_WARN("Parameter 'devicestring' is missing. Using default Value: /dev/ttyLed");
00112     _nh.param<std::string>("devicestring",_deviceString,"/dev/ttyLed");
00113 
00114     if(!_nh.hasParam("baudrate"))
00115       ROS_WARN("Parameter 'baudrate' is missing. Using default Value: 230400");
00116     _nh.param<int>("baudrate",_baudrate,230400);
00117 
00118     if(!_nh.hasParam("pubmarker"))
00119       ROS_WARN("Parameter 'pubmarker' is missing. Using default Value: true");
00120     _nh.param<bool>("pubmarker",_bPubMarker,true);
00121 
00122     if(!_nh.hasParam("marker_frame"))
00123       ROS_WARN("Parameter 'marker_frame' is missing. Using default Value: /base_link");
00124     _nh.param<std::string>("marker_frame",_sMarkerFrame,"base_link");
00125 
00126     if(!_nh.hasParam("sim_enabled"))
00127       ROS_WARN("Parameter 'sim_enabled' is missing. Using default Value: false");
00128     _nh.param<bool>("sim_enabled", _bSimEnabled, false);
00129 
00130     if(!_nh.hasParam("startup_color"))
00131     {
00132       ROS_WARN("Parameter 'startup_color' is missing. Using default Value: off");
00133       _color.r=0;_color.g=0;_color.b=0;_color.a=0;
00134     }
00135     else
00136     {
00137       _nh.getParam("startup_color", param_list);
00138       ROS_ASSERT(param_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00139       ROS_ASSERT(param_list.size() == 4);
00140 
00141       _color.r = static_cast<double>(param_list[0]);
00142       _color.g = static_cast<double>(param_list[1]);
00143       _color.b = static_cast<double>(param_list[2]);
00144       _color.a = static_cast<double>(param_list[3]);
00145     }
00146 
00147     if(!_nh.hasParam("startup_mode"))
00148       ROS_WARN("Parameter 'startup_mode' is missing. Using default Value: None");
00149     _nh.param<std::string>("startup_mode", startup_mode, "None");
00150 
00151     if(!_nh.hasParam("num_leds"))
00152             ROS_WARN("Parameter 'num_leds' is missing. Using default Value: 58");
00153           _nh.param<int>("num_leds", _num_leds, 58);
00154 
00155     int led_offset;
00156     _nh.param<int>("led_offset", led_offset, 0);
00157 
00158     //Subscribe to LightController Command Topic
00159     _sub = _nh.subscribe("command", 1, &LightControl::topicCallback, this);
00160 
00161     //Advertise light mode Service
00162     _srvServer = _nh.advertiseService("set_light", &LightControl::serviceCallback, this);
00163 
00164     //Advertise stop mode service
00165     _srvStopMode = _nh.advertiseService("stop_mode", &LightControl::stopMode, this);
00166 
00167     //Start light mode Action Server
00168     _as = new ActionServer(_nh, "set_light", boost::bind(&LightControl::actionCallback, this, _1), false);
00169     _as->start();
00170 
00171     //Advertise visualization marker topic
00172     _pubMarker = _nh.advertise<visualization_msgs::Marker>("marker",1);
00173 
00174     if(!_bSimEnabled)
00175     {
00176       //open serial port
00177       ROS_INFO("Open Port on %s",_deviceString.c_str());
00178       if(_serialIO.openPort(_deviceString, _baudrate) != -1)
00179       {
00180         ROS_INFO("Serial connection on %s succeeded.", _deviceString.c_str());
00181         status.level = 0;
00182         status.message = "light controller running";
00183 
00184         if(_deviceDriver == "cob_ledboard")
00185           p_colorO = new ColorO(&_serialIO);
00186         else if(_deviceDriver == "ms-35")
00187           p_colorO = new MS35(&_serialIO);
00188         else if(_deviceDriver == "stageprofi")
00189           p_colorO = new StageProfi(&_serialIO, _num_leds, led_offset);
00190         else
00191         {
00192           ROS_ERROR_STREAM("Unsupported devicedriver ["<<_deviceDriver<<"], falling back to sim mode");
00193           p_colorO = new ColorOSim(&_nh);
00194           status.level = 2;
00195           status.message = "Unsupported devicedriver. Running in simulation mode";
00196         }
00197         p_colorO->setMask(_invertMask);
00198         if(!p_colorO->init())
00199         {
00200           status.level = 3;
00201           status.message = "Initializing connection to driver failed";
00202           ROS_ERROR("Initializing connection to driver failed. Exiting");
00203           ret = false;
00204         }
00205       }
00206       else
00207       {
00208         ROS_WARN("Serial connection on %s failed.", _deviceString.c_str());
00209         ROS_WARN("Simulation mode enabled");
00210         p_colorO = new ColorOSim(&_nh);
00211         p_colorO->setNumLeds(_num_leds);
00212 
00213         status.level = 2;
00214         status.message = "Serial connection failed. Running in simulation mode";
00215       }
00216     }
00217     else
00218     {
00219       ROS_INFO("Simulation mode enabled");
00220       p_colorO = new ColorOSim(&_nh);
00221       p_colorO->setNumLeds(_num_leds);
00222       status.level = 0;
00223       status.message = "light controller running in simulation";
00224     }
00225 
00226     _diagnostics.status.push_back(status);
00227 
00228     if(!ret)
00229       return false;
00230 
00231     if(_bPubMarker)
00232       p_colorO->signalColorSet()->connect(boost::bind(&LightControl::markerCallback, this, _1));
00233 
00234     p_modeExecutor = new ModeExecutor(p_colorO);
00235 
00236     boost::shared_ptr<Mode> mode = ModeFactory::create(startup_mode, _color);
00237     if(mode == NULL)
00238     {
00239       p_colorO->setColor(_color);
00240     }
00241     else
00242       p_modeExecutor->execute(mode);
00243 
00244     return true;
00245   }
00246 
00247   ~LightControl()
00248   {
00249     if(p_modeExecutor != NULL)
00250     {
00251       p_modeExecutor->stop();
00252       delete p_modeExecutor;
00253     }
00254     if(p_colorO != NULL)
00255     {
00256       delete p_colorO;
00257     }
00258   }
00259 
00260   void topicCallback(cob_light::ColorRGBAArray color)
00261   {
00262       boost::mutex::scoped_lock lock(_mutex);
00263       if(p_modeExecutor->getExecutingPriority() <= _topic_priority)
00264       {
00265           p_modeExecutor->pause();
00266           if(color.colors.size() > 0)
00267           {
00268               if(color.colors.size() > 1)
00269               {
00270                   std::vector<color::rgba> colors;
00271                   for(size_t i=0; i<colors.size();i++)
00272                   {
00273                       if(color.colors[i].r <= 1.0 && color.colors[i].g <= 1.0 && color.colors[i].b <= 1.0)
00274                       {
00275                         _color.a = color.colors[i].a;
00276                         _color.r = color.colors[i].r;
00277                         _color.g = color.colors[i].g;
00278                         _color.b = color.colors[i].b;
00279                         colors.push_back(_color);
00280                       }
00281                       else
00282                         ROS_ERROR("Unsupported Color format. rgba values range is between 0.0 - 1.0");
00283                   }
00284                   p_colorO->setColorMulti(colors);
00285               }
00286               else
00287               {
00288                   if(color.colors[0].r <= 1.0 && color.colors[0].g <= 1.0 && color.colors[0].b <= 1.0)
00289                   {
00290                       _color.r = color.colors[0].r;
00291                       _color.g = color.colors[0].g;
00292                       _color.b = color.colors[0].b;
00293                       _color.a = color.colors[0].a;
00294 
00295                       p_colorO->setColor(_color);
00296                   }
00297                   else
00298                     ROS_ERROR("Unsupported Color format. rgba values range is between 0.0 - 1.0");
00299               }
00300           }
00301           else
00302             ROS_ERROR("Empty color msg received");
00303         }
00304   }
00305 
00306   bool serviceCallback(cob_light::SetLightMode::Request &req, cob_light::SetLightMode::Response &res)
00307   {
00308     boost::mutex::scoped_lock lock(_mutex);
00309     bool ret = false;
00310 
00311     //ROS_DEBUG("Service Callback [Mode: %i with prio: %i freq: %f timeout: %f pulses: %i ] [R: %f with G: %f B: %f A: %f]",
00312     //  req.mode.mode, req.mode.priority, req.mode.frequency, req.mode.timeout, req.mode.pulses,req.mode.color.r,req.mode.color.g ,req.mode.color.b,req.mode.color.a);
00313     if(req.mode.colors.size() > 0)
00314     {
00315         if(req.mode.colors[0].r > 1.0 || req.mode.colors[0].g > 1.0 ||
00316             req.mode.colors[0].b > 1.0 || req.mode.colors[0].a > 1.0)
00317         {
00318           res.active_mode = p_modeExecutor->getExecutingMode();
00319           res.active_priority = p_modeExecutor->getExecutingPriority();
00320           res.track_id = -1;
00321           ROS_ERROR("Unsupported Color format. rgba values range is between 0.0 - 1.0");
00322         }
00323         else if(req.mode.mode == cob_light::LightModes::NONE) //refactor this
00324         {
00325           p_modeExecutor->stop();
00326           _color.a = 0;
00327           //p_modeExecutor->execute(req.mode);
00328           p_colorO->setColor(_color);
00329           res.active_mode = p_modeExecutor->getExecutingMode();
00330           res.active_priority = p_modeExecutor->getExecutingPriority();
00331           ret = true;
00332         }
00333         else
00334         {
00335           uint64_t u_id = p_modeExecutor->execute(req.mode);
00336           res.active_mode = p_modeExecutor->getExecutingMode();
00337           res.active_priority = p_modeExecutor->getExecutingPriority();
00338           res.track_id = u_id;
00339           ret = true;
00340         }
00341     }
00342     return ret;
00343   }
00344 
00345   void actionCallback(const cob_light::SetLightModeGoalConstPtr &goal)
00346   {
00347     boost::mutex::scoped_lock lock(_mutex);
00348     cob_light::SetLightModeResult result;
00349     if(goal->mode.colors.size() > 0)
00350     {
00351         if(goal->mode.colors[0].r > 1.0 || goal->mode.colors[0].g > 1.0 ||
00352             goal->mode.colors[0].b > 1.0 || goal->mode.colors[0].a > 1.0)
00353         {
00354           result.active_mode = p_modeExecutor->getExecutingMode();
00355           result.active_priority = p_modeExecutor->getExecutingPriority();
00356           result.track_id = -1;
00357           _as->setAborted(result, "Unsupported Color format. rgba values range is between 0.0 - 1.0");
00358 
00359           ROS_ERROR("Unsupported Color format. rgba values range is between 0.0 - 1.0");
00360         }
00361         else if(goal->mode.mode == cob_light::LightModes::NONE)
00362         {
00363           p_modeExecutor->stop();
00364           _color.a = 0;
00365           p_colorO->setColor(_color);
00366           result.active_mode = p_modeExecutor->getExecutingMode();
00367           result.active_priority = p_modeExecutor->getExecutingPriority();
00368           result.track_id = -1;
00369           _as->setSucceeded(result, "Mode switched");
00370         }
00371         else
00372         {
00373           uint64_t u_id = p_modeExecutor->execute(goal->mode);
00374           result.active_mode = p_modeExecutor->getExecutingMode();
00375           result.active_priority = p_modeExecutor->getExecutingPriority();
00376           result.track_id = u_id;
00377           _as->setSucceeded(result, "Mode switched");
00378         }
00379     }
00380     else
00381         _as->setAborted(result, "No color available");
00382   }
00383 
00384   bool stopMode(cob_light::StopLightMode::Request &req, cob_light::StopLightMode::Response &res)
00385   {
00386       boost::mutex::scoped_lock lock(_mutex);
00387       bool ret = false;
00388       ret = p_modeExecutor->stop(req.track_id);
00389       res.active_mode = p_modeExecutor->getExecutingMode();
00390       res.active_priority = p_modeExecutor->getExecutingPriority();
00391       res.track_id = p_modeExecutor->getExecutingUId();
00392       ret = true; // TODO: really check if mode is stopped
00393       return ret;
00394   }
00395 
00396   void publish_diagnostics_cb(const ros::TimerEvent&)
00397   {
00398     _diagnostics.header.stamp = ros::Time::now();
00399     _pubDiagnostic.publish(_diagnostics);
00400   }
00401 
00402   void markerCallback(color::rgba color)
00403   {
00404     visualization_msgs::Marker marker;
00405     marker.header.frame_id = _sMarkerFrame;
00406     marker.header.stamp = ros::Time();
00407     marker.ns = "color";
00408     marker.id = 0;
00409     marker.type = visualization_msgs::Marker::SPHERE;
00410     marker.action = visualization_msgs::Marker::ADD;
00411     marker.pose.position.x = 0.5;
00412     marker.pose.position.y = 0.0;
00413     marker.pose.position.z = 0.0;
00414     marker.pose.orientation.x = 0.0;
00415     marker.pose.orientation.y = 0.0;
00416     marker.pose.orientation.z = 0.0;
00417     marker.pose.orientation.w = 1.0;
00418     marker.scale.x = 0.1;
00419     marker.scale.y = 0.1;
00420     marker.scale.z = 0.1;
00421     marker.color.a = color.a;
00422     marker.color.r = color.r;
00423     marker.color.g = color.g;
00424     marker.color.b = color.b;
00425     _pubMarker.publish(marker);
00426   }
00427 
00428 private:
00429   std::string _deviceDriver;
00430   std::string _deviceString;
00431   int _baudrate;
00432   int _invertMask;
00433   bool _bPubMarker;
00434   std::string _sMarkerFrame;
00435   bool _bSimEnabled;
00436   int _num_leds;
00437 
00438   int _topic_priority;
00439 
00440   ros::NodeHandle _nh;
00441   ros::Subscriber _sub;
00442   ros::Subscriber _sub_mode;
00443   ros::Publisher _pubMarker;
00444   ros::ServiceServer _srvServer;
00445   ros::ServiceServer _srvStopMode;
00446 
00447   diagnostic_msgs::DiagnosticArray _diagnostics;
00448   ros::Publisher _pubDiagnostic;
00449   ros::Timer _diagnostics_timer;
00450 
00451   typedef actionlib::SimpleActionServer<cob_light::SetLightModeAction> ActionServer;
00452   ActionServer *_as;
00453 
00454   color::rgba _color;
00455 
00456   IColorO* p_colorO;
00457   SerialIO _serialIO;
00458   ModeExecutor* p_modeExecutor;
00459 
00460   boost::mutex _mutex;
00461 };
00462 
00463 int main(int argc, char** argv)
00464 {
00465   // init node
00466   ros::init(argc, argv, "light_controller", ros::init_options::NoSigintHandler);
00467   signal(SIGINT, sigIntHandler);
00468 
00469   // Override XMLRPC shutdown
00470   ros::XMLRPCManager::instance()->unbind("shutdown");
00471   ros::XMLRPCManager::instance()->bind("shutdown", shutdownCallback);
00472 
00473   // create LightControl instance
00474   LightControl *lightControl = new LightControl();
00475   if(lightControl->init())
00476   {
00477     ros::AsyncSpinner spinner(1);
00478     spinner.start();
00479 
00480     while (!gShutdownRequest)
00481     {
00482       ros::Duration(0.05).sleep();
00483     }
00484 
00485     delete lightControl;
00486 
00487     ros::shutdown();
00488   }
00489 
00490   return 0;
00491 }


cob_light
Author(s): Benjamin Maidel
autogenerated on Sat Jun 8 2019 21:02:07