00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include <string>
00034 #include <ros/ros.h>
00035 #include <ros/console.h>
00036 #include <nodelet/nodelet.h>
00037 #include <image_transport/image_transport.h>
00038 #include <dynamic_reconfigure/server.h>
00039 #include <dynamic_reconfigure/SensorLevels.h>
00040 #include <diagnostic_updater/diagnostic_updater.h>
00041 #include <diagnostic_updater/publisher.h>
00042 #include <camera_calibration_parsers/parse_ini.h>
00043 #include <polled_camera/publication_server.h>
00044 #include <sensor_msgs/CameraInfo.h>
00045 
00046 #include <sensor_msgs/Image.h>
00047 #include <sensor_msgs/CameraInfo.h>
00048 #include <sensor_msgs/fill_image.h>
00049 #include <sensor_msgs/SetCameraInfo.h>
00050 
00051 #include <boost/thread.hpp>
00052 
00053 #include <prosilica_camera/ProsilicaCameraConfig.h>
00054 #include "prosilica/prosilica.h"
00055 #include "prosilica/rolling_sum.h"
00056 
00057 bool prosilica_inited = false;
00058 int num_cameras = 0;
00059 
00060 namespace prosilica_camera
00061 {
00062 
00063 class ProsilicaNodelet : public nodelet::Nodelet
00064 {
00065 
00066 public:
00067 
00068     virtual ~ProsilicaNodelet()
00069     {
00071         init_thread_.interrupt();
00072         init_thread_.join();
00073 
00074         if(camera_)
00075         {
00076             camera_->stop();
00077             camera_.reset(); 
00078         }
00079 
00080         trigger_sub_.shutdown();
00081         poll_srv_.shutdown();
00082         image_publisher_.shutdown();
00083 
00084         --num_cameras;
00085         if(num_cameras<=0)
00086         {
00087             prosilica::fini();
00088             prosilica_inited = false;
00089             num_cameras = 0;
00090         }
00091 
00092         NODELET_WARN("Unloaded prosilica camera with guid %s", hw_id_.c_str());
00093     }
00094 
00095     ProsilicaNodelet()
00096       : auto_adjust_stream_bytes_per_second_(true),
00097         count_(0),
00098         frames_dropped_total_(0), frames_completed_total_(0),
00099         frames_dropped_acc_(WINDOW_SIZE),
00100         frames_completed_acc_(WINDOW_SIZE),
00101         packets_missed_total_(0), packets_received_total_(0),
00102         packets_missed_acc_(WINDOW_SIZE),
00103         packets_received_acc_(WINDOW_SIZE)
00104     {
00105         ++num_cameras;
00106     }
00107 
00108 private:
00109 
00110     boost::shared_ptr<prosilica::Camera> camera_;
00111     boost::thread init_thread_;
00112     ros::Timer update_timer_;
00113 
00114     image_transport::CameraPublisher                           image_publisher_;
00115     polled_camera::PublicationServer                           poll_srv_;
00116     ros::ServiceServer                                         set_camera_info_srv_;
00117     ros::Subscriber                                            trigger_sub_;
00118 
00119     sensor_msgs::Image img_;
00120     sensor_msgs::CameraInfo cam_info_;
00121 
00122     std::string   frame_id_;
00123     unsigned long guid_;
00124     std::string   hw_id_;
00125     std::string   ip_address_;
00126     double        open_camera_retry_period_;
00127     std::string   trig_timestamp_topic_;
00128     ros::Time     trig_time_;
00129 
00130     
00131     double        update_rate_;
00132     int           trigger_mode_;
00133     bool          auto_adjust_stream_bytes_per_second_;
00134 
00135     tPvUint32 sensor_width_, sensor_height_;
00136     tPvUint32 max_binning_x, max_binning_y, dummy;
00137     int count_;
00138 
00139     
00140     prosilica_camera::ProsilicaCameraConfig last_config_;
00141     boost::recursive_mutex config_mutex_;
00142     typedef dynamic_reconfigure::Server<prosilica_camera::ProsilicaCameraConfig> ReconfigureServer;
00143     boost::shared_ptr<ReconfigureServer> reconfigure_server_;
00144 
00145     
00146     enum CameraState
00147     {
00148         OPENING,
00149         CAMERA_NOT_FOUND,
00150         FORMAT_ERROR,
00151         ERROR,
00152         OK
00153     }camera_state_;
00154     std::string state_info_;
00155     std::string intrinsics_;
00156     static const int WINDOW_SIZE = 100; 
00157     unsigned long frames_dropped_total_, frames_completed_total_;
00158     RollingSum<unsigned long> frames_dropped_acc_, frames_completed_acc_;
00159     unsigned long packets_missed_total_, packets_received_total_;
00160     RollingSum<unsigned long> packets_missed_acc_, packets_received_acc_;
00161 
00162     diagnostic_updater::Updater updater;
00163 
00164 
00165     virtual void onInit()
00166     {
00170         init_thread_ = boost::thread(boost::bind(&ProsilicaNodelet::onInitImpl, this));
00171 
00172     }
00173 
00174     void onInitImpl()
00175     {
00176         ros::NodeHandle& nh = getNodeHandle();
00177         ros::NodeHandle& pn = getPrivateNodeHandle();
00178 
00180         if(!prosilica_inited)
00181         {
00182             NODELET_INFO("Initializing prosilica GIGE API");
00183             prosilica::init();
00184             prosilica_inited = true;
00185         }
00186 
00188         count_ = 0;
00189         update_rate_=30;
00190         NODELET_INFO("namespace: %s", pn.getNamespace().c_str());
00191         pn.param<std::string>("frame_id", frame_id_, "/camera_optical_frame");
00192         NODELET_INFO("Loaded param frame_id: %s", frame_id_.c_str());
00193 
00194         pn.param<std::string>("guid", hw_id_, "");
00195         if(hw_id_ == "")
00196         {
00197             guid_ = 0;
00198         }
00199         else
00200         {
00201             guid_ = boost::lexical_cast<int>(hw_id_);
00202             NODELET_INFO("Loaded param guid: %lu", guid_);
00203         }
00204 
00205         pn.param<std::string>("ip_address", ip_address_, "");
00206         NODELET_INFO("Loaded ip address: %s", ip_address_.c_str());
00207 
00208         pn.param<double>("open_camera_retry_period", open_camera_retry_period_, 3.);
00209         NODELET_INFO("Retry period: %f", open_camera_retry_period_);
00210 
00211         
00212         updater.add(getName().c_str(), this, &ProsilicaNodelet::getCurrentState);
00213         NODELET_INFO("updated state");
00214         
00215         update_timer_ = nh.createTimer(ros::Rate(update_rate_).expectedCycleTime(), &ProsilicaNodelet::updateCallback, this, false ,false);
00216         update_timer_.stop();
00217         NODELET_INFO("created update timer");
00218         
00219         openCamera();
00220 
00221         
00222         ros::NodeHandle image_nh(nh);
00223         image_transport::ImageTransport image_it(image_nh);
00224         image_publisher_ = image_it.advertiseCamera("image_raw", 1);
00225         poll_srv_ = polled_camera::advertise(nh, "request_image", &ProsilicaNodelet::pollCallback, this);
00226         set_camera_info_srv_ = pn.advertiseService("set_camera_info", &ProsilicaNodelet::setCameraInfo, this);
00227         trigger_sub_ = pn.subscribe(trig_timestamp_topic_, 1, &ProsilicaNodelet::syncInCallback, this);
00228 
00229         
00230         reconfigure_server_.reset(new ReconfigureServer(config_mutex_, pn));
00231         ReconfigureServer::CallbackType f = boost::bind(&ProsilicaNodelet::reconfigureCallback, this, _1, _2);
00232         reconfigure_server_->setCallback(f);
00233     }
00234 
00235     void openCamera()
00236     {
00237         while (!camera_)
00238         {
00239             boost::lock_guard<boost::recursive_mutex> scoped_lock(config_mutex_);
00240             camera_state_ = OPENING;
00241             try
00242             {
00243                 if(guid_ != 0)
00244                 {
00245                     state_info_ = "Trying to load camera with guid " + hw_id_;
00246                     NODELET_INFO("%s", state_info_.c_str());
00247                     camera_ = boost::make_shared<prosilica::Camera>((unsigned long)guid_);
00248                     updater.setHardwareIDf("%d", guid_);
00249                     NODELET_INFO("Started Prosilica camera with guid \"%lu\"", guid_);
00250 
00251                 }
00252                 else if(!ip_address_.empty())
00253                 {
00254                     state_info_ = "Trying to load camera with ipaddress: " + ip_address_;
00255                     NODELET_INFO("%s", state_info_.c_str());
00256                     camera_ = boost::make_shared<prosilica::Camera>(ip_address_.c_str());
00257                     guid_ = camera_->guid();
00258                     hw_id_ = boost::lexical_cast<std::string>(guid_);
00259                     updater.setHardwareIDf("%d", guid_);
00260 
00261                     NODELET_INFO("Started Prosilica camera with guid \"%d\"", (int)camera_->guid());
00262                 }
00263                 else
00264                 {
00265                     updater.setHardwareID("unknown");
00266                     if(prosilica::numCameras()>0)
00267                     {
00268                         state_info_ = "Trying to load first camera found";
00269                         NODELET_INFO("%s", state_info_.c_str());
00270                         guid_ = prosilica::getGuid(0);
00271                         camera_ = boost::make_shared<prosilica::Camera>((unsigned long)guid_);
00272                         hw_id_ = boost::lexical_cast<std::string>(guid_);
00273                         updater.setHardwareIDf("%d", guid_);
00274                         NODELET_INFO("Started Prosilica camera with guid \"%d\"", (int)guid_);
00275                     }
00276                     else
00277                     {
00278                         throw std::runtime_error("Found no cameras on local subnet");
00279                     }
00280                 }
00281 
00282             }
00283             catch (std::exception& e)
00284             {
00285                 camera_state_ = CAMERA_NOT_FOUND;
00286                 std::stringstream err;
00287                 if (prosilica::numCameras() == 0)
00288                 {
00289                     err << "Found no cameras on local subnet";
00290                 }
00291                 else if (guid_ != 0)
00292                 {
00293                     err << "Unable to open prosilica camera with guid " << guid_ <<": "<<e.what();
00294                 }
00295                 else if (ip_address_ != "")
00296                 {
00297                     err << "Unable to open prosilica camera with ip address " << ip_address_ <<": "<<e.what();
00298                 }
00299 
00300                 state_info_ = err.str();
00301                 NODELET_WARN("%s", state_info_.c_str());
00302                 if(prosilica::numCameras() > 0)
00303                 {
00304                     NODELET_INFO("Available cameras:\n%s", getAvailableCameras().c_str());
00305                 }
00306                 camera_.reset();
00307 
00308             }
00309             updater.update();
00310             boost::this_thread::sleep(boost::posix_time::seconds(open_camera_retry_period_));
00311         }
00312         loadIntrinsics();
00313         start();
00314     }
00315 
00316     std::string getAvailableCameras()
00317     {
00318         std::vector<prosilica::CameraInfo> cameras = prosilica::listCameras();
00319         std::stringstream list;
00320         for (unsigned int i = 0; i < cameras.size(); ++i)
00321         {
00322             list << cameras[i].serial << " - " <<cameras[i].name<< " - Unique ID = "<<cameras[i].guid<<" IP = "<<cameras[i].ip_address<<std::endl;
00323         }
00324         return list.str();
00325     }
00326 
00327     void loadIntrinsics()
00328     {
00329         try
00330         {
00331             camera_->setKillCallback(boost::bind(&ProsilicaNodelet::kill, this, _1));
00332 
00333             if(auto_adjust_stream_bytes_per_second_ && camera_->hasAttribute("StreamBytesPerSecond"))
00334                 camera_->setAttribute("StreamBytesPerSecond", (tPvUint32)(115000000/num_cameras));
00335 
00336             
00337             std::string buffer(prosilica::Camera::USER_MEMORY_SIZE, '\0');
00338             camera_->readUserMemory(&buffer[0], prosilica::Camera::USER_MEMORY_SIZE);
00339 
00340             PvAttrRangeUint32(camera_->handle(), "BinningX", &dummy, &max_binning_x);
00341             PvAttrRangeUint32(camera_->handle(), "BinningY", &dummy, &max_binning_y);
00342             PvAttrRangeUint32(camera_->handle(), "Width",    &dummy, &sensor_width_);
00343             PvAttrRangeUint32(camera_->handle(), "Height",   &dummy, &sensor_height_);
00344 
00345 
00346             
00347             std::string camera_name;
00348             if (camera_calibration_parsers::parseCalibrationIni(buffer, camera_name, cam_info_))
00349             {
00350                 intrinsics_ = "Loaded calibration";
00351                 NODELET_INFO("Loaded calibration for camera '%s'", camera_name.c_str());
00352             }
00353             else
00354             {
00355                 intrinsics_ = "Failed to load intrinsics from camera";
00356                 NODELET_WARN("Failed to load intrinsics from camera");
00357             }
00358         }
00359         catch(std::exception &e)
00360         {
00361             camera_state_ = CAMERA_NOT_FOUND;
00362             state_info_ = e.what();
00363         }
00364     }
00365 
00366     void start()
00367     {
00368         try
00369         {
00370             switch(trigger_mode_)
00371             {
00372                 case prosilica::Software:
00373                     NODELET_INFO("starting camera %s in software trigger mode", hw_id_.c_str());
00374                     camera_->start(prosilica::Software, 1., prosilica::Continuous);
00375                     if(update_rate_ > 0)
00376                     {
00377                         update_timer_.setPeriod(ros::Rate(update_rate_).expectedCycleTime());
00378                         update_timer_.start();
00379                     }
00380                     break;
00381                 case prosilica::Freerun:
00382                     NODELET_INFO("starting camera %s in freerun trigger mode", hw_id_.c_str());
00383                     camera_->setFrameCallback(boost::bind(&ProsilicaNodelet::publishImage, this, _1));
00384                     camera_->start(prosilica::Freerun, 1., prosilica::Continuous);
00385                     break;
00386                 case prosilica::FixedRate:
00387                     NODELET_INFO("starting camera %s in fixedrate trigger mode", hw_id_.c_str());
00388                     camera_->setFrameCallback(boost::bind(&ProsilicaNodelet::publishImage, this, _1));
00389                     camera_->start(prosilica::FixedRate, update_rate_, prosilica::Continuous);
00390                     break;
00391                 case prosilica::SyncIn1:
00392                     NODELET_INFO("starting camera %s in sync1 trigger mode", hw_id_.c_str());
00393                     camera_->setFrameCallback(boost::bind(&ProsilicaNodelet::publishImage, this, _1));
00394                     camera_->start(prosilica::SyncIn1, update_rate_, prosilica::Continuous);
00395                     break;
00396                 case prosilica::SyncIn2:
00397                     NODELET_INFO("starting camera %s in sync2 trigger mode", hw_id_.c_str());
00398                     camera_->setFrameCallback(boost::bind(&ProsilicaNodelet::publishImage, this, _1));
00399                     camera_->start(prosilica::SyncIn2, update_rate_, prosilica::Continuous);
00400                     break;
00401                 default:
00402                     break;
00403             }
00404         }
00405         catch(std::exception &e)
00406         {
00407             camera_state_ = CAMERA_NOT_FOUND;
00408             state_info_ = e.what();
00409         }
00410     }
00411 
00412     void stop()
00413     {
00414         update_timer_.stop();
00415         if(!camera_)
00416             return;
00417         camera_->removeEvents();
00418         camera_->stop();
00419 
00420     }
00421 
00422     void kill(unsigned long guid)
00423     {
00424         if(guid == guid_)
00425         {
00426             NODELET_WARN("[%s] got kill request for prosilica camera %lu",getName().c_str(), guid);
00428             init_thread_.interrupt();
00429             init_thread_.join();
00430 
00431             camera_state_ = CAMERA_NOT_FOUND;
00432             state_info_ = "Prosilica camera " + hw_id_ + " disconnected";
00433             NODELET_ERROR("%s", state_info_.c_str());
00434             updater.update();
00435             boost::lock_guard<boost::recursive_mutex> scoped_lock(config_mutex_);
00436             stop();
00437             camera_.reset();
00438             init_thread_ = boost::thread(boost::bind(&ProsilicaNodelet::openCamera, this));
00439             return;
00440         }
00441     }
00442 
00443     void publishImage(tPvFrame* frame)
00444     {
00445         publishImage(frame, ros::Time::now());
00446     }
00447 
00448     void publishImage(tPvFrame* frame, ros::Time time)
00449     {
00450         camera_state_ = OK;
00451         state_info_ = "Camera operating normally";
00452         if (image_publisher_.getNumSubscribers() > 0)
00453         {
00454 
00455             if (processFrame(frame, img_, cam_info_))
00456             {
00457                 image_publisher_.publish(img_, cam_info_, time);
00458                 frames_dropped_acc_.add(0);
00459             }
00460             else
00461             {
00462                 camera_state_ = FORMAT_ERROR;
00463                 state_info_ = "Unable to process frame";
00464                 ++frames_dropped_total_;
00465                 frames_dropped_acc_.add(1);
00466             }
00467             ++frames_completed_total_;
00468             frames_completed_acc_.add(1);
00469         }
00470         updater.update();
00471     }
00472 
00473     void updateCallback(const ros::TimerEvent &event)
00474     {
00475         
00476         camera_state_ = OK;
00477         state_info_ = "Camera operating normally";
00478         if(image_publisher_.getNumSubscribers() > 0)
00479         {
00480             boost::lock_guard<boost::recursive_mutex> lock(config_mutex_);
00481             try
00482             {
00483                 tPvFrame* frame = NULL;
00484                 frame = camera_->grab(1000);
00485                 publishImage(frame, event.current_real);
00486             }
00487             catch(std::exception &e)
00488             {
00489                 camera_state_ = ERROR;
00490                 state_info_ = e.what();
00491                 NODELET_ERROR("Unable to read from camera: %s", e.what());
00492                 ++frames_dropped_total_;
00493                 frames_dropped_acc_.add(1);
00494                 updater.update();
00495                 return;
00496             }
00497         }
00498     }
00499 
00500     void pollCallback(polled_camera::GetPolledImage::Request& req,
00501                       polled_camera::GetPolledImage::Response& rsp,
00502                       sensor_msgs::Image& image, sensor_msgs::CameraInfo& info)
00503     {
00504         if (trigger_mode_ != prosilica::Software)
00505         {
00506             rsp.success = false;
00507             rsp.status_message = "Camera is not in software triggered mode";
00508             return;
00509         }
00510 
00511         last_config_.binning_x = req.binning_x;
00512         last_config_.binning_y = req.binning_y;
00513         last_config_.x_offset = req.roi.x_offset;
00514         last_config_.y_offset = req.roi.y_offset;
00515         last_config_.height   = req.roi.height;
00516         last_config_.width    = req.roi.width;
00517 
00518         reconfigureCallback(last_config_, dynamic_reconfigure::SensorLevels::RECONFIGURE_RUNNING);
00519 
00520         try
00521         {
00522             tPvFrame* frame = NULL;
00523             frame = camera_->grab(req.timeout.toSec()*100);
00524             if (processFrame(frame, image, info))
00525             {
00526                 image.header.stamp = info.header.stamp =rsp.stamp = ros::Time::now();
00527                 rsp.status_message = "Success";
00528                 rsp.success = true;
00529             }
00530             else
00531             {
00532                 rsp.success = false;
00533                 rsp.status_message = "Failed to process image";
00534                 return;
00535             }
00536         }
00537         catch(std::exception &e)
00538         {
00539             rsp.success = false;
00540             std::stringstream err;
00541             err<< "Failed to grab frame: "<<e.what();
00542             rsp.status_message = err.str();
00543             return;
00544         }
00545     }
00546 
00547     void syncInCallback (const std_msgs::HeaderConstPtr& msg)
00548     {
00549         if (trigger_mode_ != prosilica::Software)
00550         {
00551             camera_state_ = ERROR;
00552             state_info_ = "Can not sync from topic trigger unless in Software Trigger mode";
00553             NODELET_ERROR_ONCE("%s", state_info_.c_str());
00554             return;
00555         }
00556         ros::TimerEvent e;
00557         e.current_real = msg->stamp;
00558         updateCallback(e);
00559     }
00560 
00561     bool processFrame(tPvFrame* frame, sensor_msgs::Image &img, sensor_msgs::CameraInfo &cam_info)
00562     {
00564         if (frame==NULL || frame->Status != ePvErrSuccess)
00565             return false;
00566 
00567         try
00568         {
00572             tPvUint32 binning_x = 1, binning_y = 1;
00573             if (camera_->hasAttribute("BinningX"))
00574             {
00575                 camera_->getAttribute("BinningX", binning_x);
00576                 camera_->getAttribute("BinningY", binning_y);
00577             }
00578 
00579             
00580             if (frame->Format == ePvFmtBayer8 && (binning_x > 1 || binning_y > 1))
00581                 frame->Format = ePvFmtMono8;
00582 
00583             if (!frameToImage(frame, img))
00584                 return false;
00585 
00586             
00587             cam_info.binning_x = binning_x;
00588             cam_info.binning_y = binning_y;
00589             
00590             cam_info.roi.x_offset = frame->RegionX * binning_x;
00591             cam_info.roi.y_offset = frame->RegionY * binning_y;
00592             cam_info.roi.height = frame->Height * binning_y;
00593             cam_info.roi.width = frame->Width * binning_x;
00594             cam_info.roi.do_rectify = (frame->Height != sensor_height_ / binning_y) ||
00595                                        (frame->Width  != sensor_width_  / binning_x);
00596 
00597             if(auto_adjust_stream_bytes_per_second_ && camera_->hasAttribute("StreamBytesPerSecond"))
00598                 camera_->setAttribute("StreamBytesPerSecond", (tPvUint32)(115000000/num_cameras));
00599         }
00600         catch(std::exception &e)
00601         {
00602             return false;
00603         }
00604 
00605         count_++;
00606         return true;
00607     }
00608 
00609     bool frameToImage(tPvFrame* frame, sensor_msgs::Image &image)
00610     {
00611         
00612         static const char* BAYER_ENCODINGS[] = { "bayer_rggb8", "bayer_gbrg8", "bayer_grbg8", "bayer_bggr8" };
00613 
00614         std::string encoding;
00615         if (frame->Format == ePvFmtMono8)       encoding = sensor_msgs::image_encodings::MONO8;
00616         else if (frame->Format == ePvFmtBayer8) encoding = BAYER_ENCODINGS[frame->BayerPattern];
00617         else if (frame->Format == ePvFmtRgb24)  encoding = sensor_msgs::image_encodings::RGB8;
00618         else if (frame->Format == ePvFmtBgr24)  encoding = sensor_msgs::image_encodings::BGR8;
00619         else if (frame->Format == ePvFmtRgba32) encoding = sensor_msgs::image_encodings::RGBA8;
00620         else if (frame->Format == ePvFmtBgra32) encoding = sensor_msgs::image_encodings::BGRA8;
00621         else {
00622         NODELET_WARN("Received frame with unsupported pixel format %d", frame->Format);
00623         return false;
00624       }
00625 
00626       if(frame->ImageSize == 0 || frame->Height == 0)
00627           return false;
00628       uint32_t step = frame->ImageSize / frame->Height;
00629       return sensor_msgs::fillImage(image, encoding, frame->Height, frame->Width, step, frame->ImageBuffer);
00630     }
00631 
00632     bool setCameraInfo(sensor_msgs::SetCameraInfoRequest &req, sensor_msgs::SetCameraInfoResponse &rsp)
00633     {
00634         NODELET_INFO("New camera info received");
00635         sensor_msgs::CameraInfo &info = req.camera_info;
00636 
00637         
00638         if (info.width != sensor_width_ || info.height != sensor_height_)
00639         {
00640             rsp.success = false;
00641             rsp.status_message = (boost::format("Camera_info resolution %ix%i does not match current video "
00642                                                 "setting, camera running at resolution %ix%i.")
00643                                                  % info.width % info.height % sensor_width_ % sensor_height_).str();
00644             NODELET_ERROR("%s", rsp.status_message.c_str());
00645             return true;
00646         }
00647 
00648         stop();
00649 
00650         std::string cam_name = "prosilica";
00651         cam_name += hw_id_;
00652         std::stringstream ini_stream;
00653         if (!camera_calibration_parsers::writeCalibrationIni(ini_stream, cam_name, info))
00654         {
00655             rsp.status_message = "Error formatting camera_info for storage.";
00656             rsp.success = false;
00657         }
00658         else
00659         {
00660             std::string ini = ini_stream.str();
00661             if (ini.size() > prosilica::Camera::USER_MEMORY_SIZE)
00662             {
00663                 rsp.success = false;
00664                 rsp.status_message = "Unable to write camera_info to camera memory, exceeded storage capacity.";
00665             }
00666             else
00667             {
00668                 try
00669                 {
00670                     camera_->writeUserMemory(ini.c_str(), ini.size());
00671                     cam_info_ = info;
00672                     rsp.success = true;
00673                 }
00674                 catch (prosilica::ProsilicaException &e)
00675                 {
00676                     rsp.success = false;
00677                     rsp.status_message = e.what();
00678                 }
00679             }
00680         }
00681         if (!rsp.success)
00682         NODELET_ERROR("%s", rsp.status_message.c_str());
00683 
00684         start();
00685 
00686         return true;
00687     }
00688 
00689     void reconfigureCallback(prosilica_camera::ProsilicaCameraConfig &config, uint32_t level)
00690     {
00691         NODELET_DEBUG("Reconfigure request received");
00692 
00693         if (level >= (uint32_t)dynamic_reconfigure::SensorLevels::RECONFIGURE_STOP)
00694             stop();
00695 
00697         if (config.trigger_mode == "streaming")
00698         {
00699             trigger_mode_ = prosilica::Freerun;
00700             update_rate_ = 1.; 
00701         }
00702         else if (config.trigger_mode == "syncin1")
00703         {
00704             trigger_mode_ = prosilica::SyncIn1;
00705             update_rate_ = config.trig_rate;
00706         }
00707         else if (config.trigger_mode == "syncin2")
00708         {
00709             trigger_mode_ = prosilica::SyncIn2;
00710             update_rate_ = config.trig_rate;
00711         }
00712         else if (config.trigger_mode == "fixedrate")
00713         {
00714             trigger_mode_ = prosilica::FixedRate;
00715             update_rate_ = config.trig_rate;
00716         }
00717         else if (config.trigger_mode == "software")
00718         {
00719             trigger_mode_ = prosilica::Software;
00720             update_rate_ = config.trig_rate;
00721         }
00722 
00723         else if (config.trigger_mode == "polled")
00724         {
00725             trigger_mode_ = prosilica::Software;
00726             update_rate_ = 0;
00727         }
00728         else if (config.trigger_mode == "triggered")
00729         {
00730             trigger_mode_ = prosilica::Software;
00731             update_rate_ = 0;
00732         }
00733         else
00734         {
00735             NODELET_ERROR("Invalid trigger mode '%s' in reconfigure request", config.trigger_mode.c_str());
00736         }
00737 
00738         if(config.trig_timestamp_topic != last_config_.trig_timestamp_topic)
00739         {
00740             trigger_sub_.shutdown();
00741             trig_timestamp_topic_ = config.trig_timestamp_topic;
00742         }
00743 
00744         if(!trigger_sub_ && config.trigger_mode == "triggered")
00745         {
00746             trigger_sub_ = ros::NodeHandle().subscribe(trig_timestamp_topic_, 1, &ProsilicaNodelet::syncInCallback, this);
00747         }
00748 
00749 
00750         
00751         if (config.auto_exposure)
00752         {
00753             camera_->setExposure(0, prosilica::Auto);
00754             if (camera_->hasAttribute("ExposureAutoMax"))
00755             {
00756                 tPvUint32 us = config.exposure_auto_max*1000000. + 0.5;
00757                 camera_->setAttribute("ExposureAutoMax", us);
00758             }
00759             if (camera_->hasAttribute("ExposureAutoTarget"))
00760                 camera_->setAttribute("ExposureAutoTarget", (tPvUint32)config.exposure_auto_target);
00761         }
00762         else
00763         {
00764             unsigned us = config.exposure*1000000. + 0.5;
00765             camera_->setExposure(us, prosilica::Manual);
00766             camera_->setAttribute("ExposureValue", (tPvUint32)us);
00767         }
00768 
00769         
00770         if (config.auto_gain)
00771         {
00772             if (camera_->hasAttribute("GainAutoMax"))
00773             {
00774                 camera_->setGain(0, prosilica::Auto);
00775                 camera_->setAttribute("GainAutoMax", (tPvUint32)config.gain_auto_max);
00776                 camera_->setAttribute("GainAutoTarget", (tPvUint32)config.gain_auto_target);
00777             }
00778             else
00779             {
00780                 tPvUint32 major, minor;
00781                 camera_->getAttribute("FirmwareVerMajor", major);
00782                 camera_->getAttribute("FirmwareVerMinor", minor);
00783                 NODELET_WARN("Auto gain not available for this camera. Auto gain is available "
00784                 "on firmware versions 1.36 and above. You are running version %u.%u.",
00785                 (unsigned)major, (unsigned)minor);
00786                 config.auto_gain = false;
00787             }
00788         }
00789         else
00790         {
00791             camera_->setGain(config.gain, prosilica::Manual);
00792             camera_->setAttribute("GainValue", (tPvUint32)config.gain);
00793         }
00794 
00795         
00796         if (config.auto_whitebalance)
00797         {
00798             if (camera_->hasAttribute("WhitebalMode"))
00799                 camera_->setWhiteBalance(0, 0, prosilica::Auto);
00800             else
00801             {
00802                 NODELET_WARN("Auto white balance not available for this camera.");
00803                 config.auto_whitebalance = false;
00804             }
00805         }
00806         else
00807         {
00808             camera_->setWhiteBalance(config.whitebalance_blue, config.whitebalance_red, prosilica::Manual);
00809             if (camera_->hasAttribute("WhitebalValueRed"))
00810                 camera_->setAttribute("WhitebalValueRed", (tPvUint32)config.whitebalance_red);
00811             if (camera_->hasAttribute("WhitebalValueBlue"))
00812                 camera_->setAttribute("WhitebalValueBlue", (tPvUint32)config.whitebalance_blue);
00813         }
00814 
00815         
00816         if (camera_->hasAttribute("BinningX"))
00817         {
00818             config.binning_x = std::min(config.binning_x, (int)max_binning_x);
00819             config.binning_y = std::min(config.binning_y, (int)max_binning_y);
00820 
00821             camera_->setBinning(config.binning_x, config.binning_y);
00822         }
00823         else if (config.binning_x > 1 || config.binning_y > 1)
00824         {
00825             NODELET_WARN("Binning not available for this camera.");
00826             config.binning_x = config.binning_y = 1;
00827         }
00828 
00829         
00830         
00831         config.x_offset = std::min(config.x_offset, (int)sensor_width_ - 1);
00832         config.y_offset = std::min(config.y_offset, (int)sensor_height_ - 1);
00833         config.width  = std::min(config.width, (int)sensor_width_ - config.x_offset);
00834         config.height = std::min(config.height, (int)sensor_height_ - config.y_offset);
00835         
00836         int width  = config.width  ? config.width  : sensor_width_  - config.x_offset;
00837         int height = config.height ? config.height : sensor_height_ - config.y_offset;
00838 
00839         
00841         int x_offset = config.x_offset / config.binning_x;
00842         int y_offset = config.y_offset / config.binning_y;
00843         unsigned int right_x  = (config.x_offset + width  + config.binning_x - 1) / config.binning_x;
00844         unsigned int bottom_y = (config.y_offset + height + config.binning_y - 1) / config.binning_y;
00845         
00846         right_x = std::min(right_x, (unsigned)(sensor_width_ / config.binning_x));
00847         bottom_y = std::min(bottom_y, (unsigned)(sensor_height_ / config.binning_y));
00848         width = right_x - x_offset;
00849         height = bottom_y - y_offset;
00850 
00851         camera_->setRoi(x_offset, y_offset, width, height);
00852 
00853       
00854       img_.header.frame_id = cam_info_.header.frame_id = config.frame_id;
00855 
00856         
00857         
00858         
00859         
00860         auto_adjust_stream_bytes_per_second_ = config.auto_adjust_stream_bytes_per_second;
00861         if (!auto_adjust_stream_bytes_per_second_)
00862             camera_->setAttribute("StreamBytesPerSecond", (tPvUint32)config.stream_bytes_per_second);
00863         else
00864             camera_->setAttribute("StreamBytesPerSecond", (tPvUint32)(115000000/num_cameras));
00865 
00868         if (level >= (uint32_t)dynamic_reconfigure::SensorLevels::RECONFIGURE_STOP)
00869         {
00870             try
00871             {
00872                 start();
00873             }
00874             catch(std::exception &e)
00875             {
00876                 NODELET_ERROR("Invalid settings: %s", e.what());
00877                 config = last_config_;
00878             }
00879         }
00880 
00881         last_config_ = config;
00882     }
00883 
00884     void getCurrentState(diagnostic_updater::DiagnosticStatusWrapper &stat)
00885     {
00886         stat.add("Serial", guid_);
00887         stat.add("Info", state_info_);
00888         stat.add("Intrinsics", intrinsics_);
00889         stat.add("Total frames dropped", frames_dropped_total_);
00890         stat.add("Total frames", frames_completed_total_);
00891 
00892         if(frames_completed_total_>0)
00893         {
00894             stat.add("Total % frames dropped", 100.*(double)frames_dropped_total_/frames_completed_total_);
00895         }
00896         if(frames_completed_acc_.sum()>0)
00897         {
00898             stat.add("Recent % frames dropped", 100.*frames_dropped_acc_.sum()/frames_completed_acc_.sum());
00899         }
00900 
00901         switch (camera_state_)
00902         {
00903             case OPENING:
00904                 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Opening camera");
00905                 break;
00906             case OK:
00907                 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Camera operating normally");
00908                 break;
00909             case CAMERA_NOT_FOUND:
00910                 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "Can not find camera %d", guid_ );
00911                 stat.add("Available Cameras", getAvailableCameras());
00912                 break;
00913             case FORMAT_ERROR:
00914                 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Problem retrieving frame");
00915                 break;
00916             case ERROR:
00917                 stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, "Camera has encountered an error");
00918                 break;
00919             default:
00920                 break;
00921         }
00922     }
00923 };
00924 }
00925 
00926 #include <pluginlib/class_list_macros.h>
00927 PLUGINLIB_EXPORT_CLASS(prosilica_camera::ProsilicaNodelet, nodelet::Nodelet);
00928