00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <sstream>
00022 #include <math.h>
00023 #include <signal.h>
00024
00025
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
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
00045 #include <serialIO.h>
00046
00047
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;
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
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
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
00159 _sub = _nh.subscribe("command", 1, &LightControl::topicCallback, this);
00160
00161
00162 _srvServer = _nh.advertiseService("set_light", &LightControl::serviceCallback, this);
00163
00164
00165 _srvStopMode = _nh.advertiseService("stop_mode", &LightControl::stopMode, this);
00166
00167
00168 _as = new ActionServer(_nh, "set_light", boost::bind(&LightControl::actionCallback, this, _1), false);
00169 _as->start();
00170
00171
00172 _pubMarker = _nh.advertise<visualization_msgs::Marker>("marker",1);
00173
00174 if(!_bSimEnabled)
00175 {
00176
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
00312
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)
00324 {
00325 p_modeExecutor->stop();
00326 _color.a = 0;
00327
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;
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
00466 ros::init(argc, argv, "light_controller", ros::init_options::NoSigintHandler);
00467 signal(SIGINT, sigIntHandler);
00468
00469
00470 ros::XMLRPCManager::instance()->unbind("shutdown");
00471 ros::XMLRPCManager::instance()->bind("shutdown", shutdownCallback);
00472
00473
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 }