38 #include <dynamic_reconfigure/server.h> 39 #include <dynamic_reconfigure/SensorLevels.h> 44 #include <sensor_msgs/CameraInfo.h> 46 #include <sensor_msgs/Image.h> 47 #include <sensor_msgs/CameraInfo.h> 49 #include <sensor_msgs/SetCameraInfo.h> 51 #include <boost/thread.hpp> 53 #include <prosilica_camera/ProsilicaCameraConfig.h> 191 pn.
param<std::string>(
"frame_id",
frame_id_,
"/camera_optical_frame");
192 NODELET_INFO(
"Loaded param frame_id: %s", frame_id_.c_str());
201 guid_ = boost::lexical_cast<
int>(
hw_id_);
206 NODELET_INFO(
"Loaded ip address: %s", ip_address_.c_str());
209 NODELET_INFO(
"Retry period: %f", open_camera_retry_period_);
216 update_timer_.
stop();
232 reconfigure_server_->setCallback(f);
239 boost::lock_guard<boost::recursive_mutex> scoped_lock(config_mutex_);
245 state_info_ =
"Trying to load camera with guid " +
hw_id_;
247 camera_ = boost::make_shared<prosilica::Camera>((
unsigned long)guid_);
249 NODELET_INFO(
"Started Prosilica camera with guid \"%lu\"", guid_);
252 else if(!ip_address_.empty())
254 state_info_ =
"Trying to load camera with ipaddress: " +
ip_address_;
256 camera_ = boost::make_shared<prosilica::Camera>(ip_address_.c_str());
257 guid_ = camera_->guid();
258 hw_id_ = boost::lexical_cast<std::string>(
guid_);
261 NODELET_INFO(
"Started Prosilica camera with guid \"%d\"", (
int)camera_->guid());
268 state_info_ =
"Trying to load first camera found";
271 camera_ = boost::make_shared<prosilica::Camera>((
unsigned long)guid_);
272 hw_id_ = boost::lexical_cast<std::string>(
guid_);
274 NODELET_INFO(
"Started Prosilica camera with guid \"%d\"", (
int)guid_);
278 throw std::runtime_error(
"Found no cameras on local subnet");
283 catch (std::exception& e)
286 std::stringstream err;
289 err <<
"Found no cameras on local subnet";
293 err <<
"Unable to open prosilica camera with guid " << guid_ <<
": "<<e.what();
295 else if (ip_address_ !=
"")
297 err <<
"Unable to open prosilica camera with ip address " << ip_address_ <<
": "<<e.what();
300 state_info_ = err.str();
310 boost::this_thread::sleep(boost::posix_time::seconds(open_camera_retry_period_));
319 std::stringstream list;
320 for (
unsigned int i = 0; i < cameras.size(); ++i)
322 list << cameras[i].serial <<
" - " <<cameras[i].name<<
" - Unique ID = "<<cameras[i].guid<<
" IP = "<<cameras[i].ip_address<<std::endl;
333 if(auto_adjust_stream_bytes_per_second_ && camera_->hasAttribute(
"StreamBytesPerSecond"))
334 camera_->setAttribute(
"StreamBytesPerSecond", (tPvUint32)(115000000/
num_cameras));
347 std::string camera_name;
350 intrinsics_ =
"Loaded calibration";
351 NODELET_INFO(
"Loaded calibration for camera '%s'", camera_name.c_str());
355 intrinsics_ =
"Failed to load intrinsics from camera";
359 catch(std::exception &e)
362 state_info_ = e.what();
370 switch(trigger_mode_)
373 NODELET_INFO(
"starting camera %s in software trigger mode", hw_id_.c_str());
378 update_timer_.
start();
382 NODELET_INFO(
"starting camera %s in freerun trigger mode", hw_id_.c_str());
387 NODELET_INFO(
"starting camera %s in fixedrate trigger mode", hw_id_.c_str());
392 NODELET_INFO(
"starting camera %s in sync1 trigger mode", hw_id_.c_str());
397 NODELET_INFO(
"starting camera %s in sync2 trigger mode", hw_id_.c_str());
405 catch(std::exception &e)
408 state_info_ = e.what();
414 update_timer_.
stop();
417 camera_->removeEvents();
428 init_thread_.interrupt();
432 state_info_ =
"Prosilica camera " + hw_id_ +
" disconnected";
435 boost::lock_guard<boost::recursive_mutex> scoped_lock(config_mutex_);
451 state_info_ =
"Camera operating normally";
457 image_publisher_.
publish(img_, cam_info_, time);
458 frames_dropped_acc_.
add(0);
463 state_info_ =
"Unable to process frame";
465 frames_dropped_acc_.
add(1);
468 frames_completed_acc_.
add(1);
477 state_info_ =
"Camera operating normally";
480 boost::lock_guard<boost::recursive_mutex> lock(config_mutex_);
484 frame = camera_->grab(1000);
487 catch(std::exception &e)
489 camera_state_ =
ERROR;
490 state_info_ = e.what();
493 frames_dropped_acc_.
add(1);
501 polled_camera::GetPolledImage::Response& rsp,
502 sensor_msgs::Image& image, sensor_msgs::CameraInfo& info)
507 rsp.status_message =
"Camera is not in software triggered mode";
511 last_config_.binning_x = req.binning_x;
512 last_config_.binning_y = req.binning_y;
513 last_config_.x_offset = req.roi.x_offset;
514 last_config_.y_offset = req.roi.y_offset;
515 last_config_.height = req.roi.height;
516 last_config_.width = req.roi.width;
523 frame = camera_->grab(req.timeout.toSec()*100);
526 image.header.stamp = info.header.stamp =rsp.stamp =
ros::Time::now();
527 rsp.status_message =
"Success";
533 rsp.status_message =
"Failed to process image";
537 catch(std::exception &e)
540 std::stringstream err;
541 err<<
"Failed to grab frame: "<<e.what();
542 rsp.status_message = err.str();
551 camera_state_ =
ERROR;
552 state_info_ =
"Can not sync from topic trigger unless in Software Trigger mode";
572 tPvUint32 binning_x = 1, binning_y = 1;
573 if (camera_->hasAttribute(
"BinningX"))
575 camera_->getAttribute(
"BinningX", binning_x);
576 camera_->getAttribute(
"BinningY", binning_y);
587 cam_info.binning_x = binning_x;
588 cam_info.binning_y = binning_y;
590 cam_info.roi.x_offset = frame->
RegionX * binning_x;
591 cam_info.roi.y_offset = frame->
RegionY * binning_y;
592 cam_info.roi.height = frame->
Height * binning_y;
593 cam_info.roi.width = frame->
Width * binning_x;
594 cam_info.roi.do_rectify = (frame->
Height != sensor_height_ / binning_y) ||
595 (frame->
Width != sensor_width_ / binning_x);
597 if(auto_adjust_stream_bytes_per_second_ && camera_->hasAttribute(
"StreamBytesPerSecond"))
598 camera_->setAttribute(
"StreamBytesPerSecond", (tPvUint32)(115000000/
num_cameras));
600 catch(std::exception &e)
612 static const char* BAYER_ENCODINGS[] = {
"bayer_rggb8",
"bayer_gbrg8",
"bayer_grbg8",
"bayer_bggr8" };
614 std::string encoding;
632 bool setCameraInfo(sensor_msgs::SetCameraInfoRequest &req, sensor_msgs::SetCameraInfoResponse &rsp)
635 sensor_msgs::CameraInfo &info = req.camera_info;
638 if (info.width != sensor_width_ || info.height != sensor_height_)
641 rsp.status_message = (boost::format(
"Camera_info resolution %ix%i does not match current video " 642 "setting, camera running at resolution %ix%i.")
643 % info.width % info.height % sensor_width_ %
sensor_height_).str();
650 std::string cam_name =
"prosilica";
652 std::stringstream ini_stream;
655 rsp.status_message =
"Error formatting camera_info for storage.";
660 std::string ini = ini_stream.str();
664 rsp.status_message =
"Unable to write camera_info to camera memory, exceeded storage capacity.";
670 camera_->writeUserMemory(ini.c_str(), ini.size());
677 rsp.status_message = e.what();
693 if (level >= (uint32_t)dynamic_reconfigure::SensorLevels::RECONFIGURE_STOP)
697 if (config.trigger_mode ==
"streaming")
702 else if (config.trigger_mode ==
"syncin1")
705 update_rate_ = config.trig_rate;
707 else if (config.trigger_mode ==
"syncin2")
710 update_rate_ = config.trig_rate;
712 else if (config.trigger_mode ==
"fixedrate")
715 update_rate_ = config.trig_rate;
717 else if (config.trigger_mode ==
"software")
720 update_rate_ = config.trig_rate;
723 else if (config.trigger_mode ==
"polled")
728 else if (config.trigger_mode ==
"triggered")
735 NODELET_ERROR(
"Invalid trigger mode '%s' in reconfigure request", config.trigger_mode.c_str());
738 if(config.trig_timestamp_topic != last_config_.trig_timestamp_topic)
741 trig_timestamp_topic_ = config.trig_timestamp_topic;
744 if(!trigger_sub_ && config.trigger_mode ==
"triggered")
751 if (config.auto_exposure)
754 if (camera_->hasAttribute(
"ExposureAutoMax"))
756 tPvUint32 us = config.exposure_auto_max*1000000. + 0.5;
757 camera_->setAttribute(
"ExposureAutoMax", us);
759 if (camera_->hasAttribute(
"ExposureAutoTarget"))
760 camera_->setAttribute(
"ExposureAutoTarget", (tPvUint32)config.exposure_auto_target);
764 unsigned us = config.exposure*1000000. + 0.5;
766 camera_->setAttribute(
"ExposureValue", (tPvUint32)us);
770 if (config.auto_gain)
772 if (camera_->hasAttribute(
"GainAutoMax"))
775 camera_->setAttribute(
"GainAutoMax", (tPvUint32)config.gain_auto_max);
776 camera_->setAttribute(
"GainAutoTarget", (tPvUint32)config.gain_auto_target);
780 tPvUint32 major, minor;
781 camera_->getAttribute(
"FirmwareVerMajor", major);
782 camera_->getAttribute(
"FirmwareVerMinor", minor);
783 NODELET_WARN(
"Auto gain not available for this camera. Auto gain is available " 784 "on firmware versions 1.36 and above. You are running version %u.%u.",
785 (
unsigned)major, (
unsigned)minor);
786 config.auto_gain =
false;
792 camera_->setAttribute(
"GainValue", (tPvUint32)config.gain);
796 if (config.auto_whitebalance)
798 if (camera_->hasAttribute(
"WhitebalMode"))
802 NODELET_WARN(
"Auto white balance not available for this camera.");
803 config.auto_whitebalance =
false;
808 camera_->setWhiteBalance(config.whitebalance_blue, config.whitebalance_red,
prosilica::Manual);
809 if (camera_->hasAttribute(
"WhitebalValueRed"))
810 camera_->setAttribute(
"WhitebalValueRed", (tPvUint32)config.whitebalance_red);
811 if (camera_->hasAttribute(
"WhitebalValueBlue"))
812 camera_->setAttribute(
"WhitebalValueBlue", (tPvUint32)config.whitebalance_blue);
816 if (camera_->hasAttribute(
"BinningX"))
818 config.binning_x = std::min(config.binning_x, (
int)max_binning_x);
819 config.binning_y = std::min(config.binning_y, (
int)max_binning_y);
821 camera_->setBinning(config.binning_x, config.binning_y);
823 else if (config.binning_x > 1 || config.binning_y > 1)
826 config.binning_x = config.binning_y = 1;
831 config.x_offset = std::min(config.x_offset, (
int)sensor_width_ - 1);
832 config.y_offset = std::min(config.y_offset, (
int)sensor_height_ - 1);
833 config.width = std::min(config.width, (
int)sensor_width_ - config.x_offset);
834 config.height = std::min(config.height, (
int)sensor_height_ - config.y_offset);
836 int width = config.width ? config.width : sensor_width_ - config.x_offset;
837 int height = config.height ? config.height : sensor_height_ - config.y_offset;
841 int x_offset = config.x_offset / config.binning_x;
842 int y_offset = config.y_offset / config.binning_y;
843 unsigned int right_x = (config.x_offset + width + config.binning_x - 1) / config.binning_x;
844 unsigned int bottom_y = (config.y_offset + height + config.binning_y - 1) / config.binning_y;
846 right_x = std::min(right_x, (
unsigned)(sensor_width_ / config.binning_x));
847 bottom_y = std::min(bottom_y, (
unsigned)(sensor_height_ / config.binning_y));
848 width = right_x - x_offset;
849 height = bottom_y - y_offset;
851 camera_->setRoi(x_offset, y_offset, width, height);
854 img_.header.frame_id = cam_info_.header.frame_id = config.frame_id;
860 auto_adjust_stream_bytes_per_second_ = config.auto_adjust_stream_bytes_per_second;
861 if (!auto_adjust_stream_bytes_per_second_)
862 camera_->setAttribute(
"StreamBytesPerSecond", (tPvUint32)config.stream_bytes_per_second);
864 camera_->setAttribute(
"StreamBytesPerSecond", (tPvUint32)(115000000/
num_cameras));
868 if (level >= (uint32_t)dynamic_reconfigure::SensorLevels::RECONFIGURE_STOP)
874 catch(std::exception &e)
881 last_config_ = config;
886 stat.
add(
"Serial", guid_);
887 stat.
add(
"Info", state_info_);
888 stat.
add(
"Intrinsics", intrinsics_);
889 stat.
add(
"Total frames dropped", frames_dropped_total_);
890 stat.
add(
"Total frames", frames_completed_total_);
892 if(frames_completed_total_>0)
894 stat.
add(
"Total % frames dropped", 100.*(
double)frames_dropped_total_/frames_completed_total_);
896 if(frames_completed_acc_.
sum()>0)
898 stat.
add(
"Recent % frames dropped", 100.*frames_dropped_acc_.
sum()/frames_completed_acc_.
sum());
901 switch (camera_state_)
904 stat.
summary(diagnostic_msgs::DiagnosticStatus::WARN,
"Opening camera");
907 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"Camera operating normally");
910 stat.
summaryf(diagnostic_msgs::DiagnosticStatus::ERROR,
"Can not find camera %d", guid_ );
914 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Problem retrieving frame");
917 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Camera has encountered an error");
static bool fillImage(Image &image, const std::string &encoding_arg, uint32_t rows_arg, uint32_t cols_arg, uint32_t step_arg, const void *data_arg)
void getCurrentState(diagnostic_updater::DiagnosticStatusWrapper &stat)
void publish(const sensor_msgs::Image &image, const sensor_msgs::CameraInfo &info) const
tPvErr PVDECL PvAttrRangeUint32(tPvHandle Camera, const char *Name, tPvUint32 *pMin, tPvUint32 *pMax)
double open_camera_retry_period_
#define NODELET_ERROR(...)
RollingSum< unsigned long > frames_completed_acc_
enum prosilica_camera::ProsilicaNodelet::CameraState camera_state_
#define NODELET_WARN(...)
unsigned long frames_dropped_total_
bool auto_adjust_stream_bytes_per_second_
void summary(unsigned char lvl, const std::string s)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
RollingSum< unsigned long > packets_missed_acc_
uint32_t getNumSubscribers() const
void setHardwareID(const std::string &hwid)
tPvBayerPattern BayerPattern
bool processFrame(tPvFrame *frame, sensor_msgs::Image &img, sensor_msgs::CameraInfo &cam_info)
void syncInCallback(const std_msgs::HeaderConstPtr &msg)
void setPeriod(const Duration &period, bool reset=true)
const std::string & getName() const
ros::Subscriber trigger_sub_
void add(const std::string &name, TaskFunction f)
uint64_t getGuid(size_t i)
sensor_msgs::CameraInfo cam_info_
boost::shared_ptr< prosilica::Camera > camera_
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
unsigned long packets_received_total_
boost::shared_ptr< ReconfigureServer > reconfigure_server_
void publishImage(tPvFrame *frame, ros::Time time)
void publishImage(tPvFrame *frame)
std::string trig_timestamp_topic_
ros::NodeHandle & getPrivateNodeHandle() const
void summaryf(unsigned char lvl, const char *format,...)
virtual ~ProsilicaNodelet()
PLUGINLIB_EXPORT_CLASS(prosilica_camera::ProsilicaNodelet, nodelet::Nodelet)
void pollCallback(polled_camera::GetPolledImage::Request &req, polled_camera::GetPolledImage::Response &rsp, sensor_msgs::Image &image, sensor_msgs::CameraInfo &info)
PublicationServer advertise(ros::NodeHandle &nh, const std::string &service, const PublicationServer::DriverCallback &cb, const ros::VoidPtr &tracked_object=ros::VoidPtr())
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
RollingSum< unsigned long > packets_received_acc_
static const size_t USER_MEMORY_SIZE
Data must have size <= USER_MEMORY_SIZE bytes.
image_transport::CameraPublisher image_publisher_
ros::ServiceServer set_camera_info_srv_
std::vector< CameraInfo > listCameras()
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
#define NODELET_ERROR_ONCE(...)
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
const std::string & getNamespace() const
bool writeCalibrationIni(std::ostream &out, const std::string &camera_name, const sensor_msgs::CameraInfo &cam_info)
polled_camera::PublicationServer poll_srv_
void kill(unsigned long guid)
ros::NodeHandle & getNodeHandle() const
unsigned long packets_missed_total_
bool setCameraInfo(sensor_msgs::SetCameraInfoRequest &req, sensor_msgs::SetCameraInfoResponse &rsp)
#define NODELET_INFO(...)
boost::recursive_mutex config_mutex_
unsigned long frames_completed_total_
bool frameToImage(tPvFrame *frame, sensor_msgs::Image &image)
dynamic_reconfigure::Server< prosilica_camera::ProsilicaCameraConfig > ReconfigureServer
diagnostic_updater::Updater updater
prosilica_camera::ProsilicaCameraConfig last_config_
bool parseCalibrationIni(const std::string &buffer, std::string &camera_name, sensor_msgs::CameraInfo &cam_info)
void add(const std::string &key, const T &val)
void setHardwareIDf(const char *format,...)
std::string getAvailableCameras()
void updateCallback(const ros::TimerEvent &event)
boost::thread init_thread_
#define NODELET_DEBUG(...)
RollingSum< unsigned long > frames_dropped_acc_
static const int WINDOW_SIZE
void reconfigureCallback(prosilica_camera::ProsilicaCameraConfig &config, uint32_t level)