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 <driver_base/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_, driver_base::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)driver_base::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)driver_base::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