6 #include <dynamic_reconfigure/config_tools.h> 8 #include <Zivid/Firmware.h> 9 #include <Zivid/Frame2D.h> 10 #include <Zivid/Settings2D.h> 11 #include <Zivid/Version.h> 12 #include <Zivid/CaptureAssistant.h> 13 #include <Zivid/Experimental/Calibration.h> 15 #include <boost/algorithm/string.hpp> 16 #include <boost/predef.h> 24 sensor_msgs::PointField createPointField(std::string name, uint32_t offset, uint8_t datatype, uint32_t count)
26 sensor_msgs::PointField point_field;
27 point_field.name = name;
28 point_field.offset = offset;
29 point_field.datatype = datatype;
30 point_field.count = count;
36 return BOOST_ENDIAN_BIG_BYTE;
40 void fillCommonMsgFields(T& msg,
const std_msgs::Header& header, std::size_t width, std::size_t height)
43 msg.height =
static_cast<uint32_t
>(height);
44 msg.width =
static_cast<uint32_t
>(width);
45 msg.is_bigendian = big_endian();
48 sensor_msgs::ImagePtr makeImage(
const std_msgs::Header& header,
const std::string& encoding, std::size_t width,
51 auto image = boost::make_shared<sensor_msgs::Image>();
52 fillCommonMsgFields(*image, header, width, height);
53 image->encoding = encoding;
56 image->step =
static_cast<uint32_t
>(bytes_per_pixel * width);
60 template <
typename Ziv
idDataType>
61 sensor_msgs::ImagePtr makePointCloudImage(
const Zivid::PointCloud& point_cloud,
const std_msgs::Header& header,
62 const std::string& encoding)
64 auto image = makeImage(header, encoding, point_cloud.width(), point_cloud.height());
65 image->data.resize(image->step * image->height);
66 point_cloud.copyData<ZividDataType>(
reinterpret_cast<ZividDataType*
>(image->data.data()));
72 switch (camera_status)
77 return "Disconnected";
92 , use_latched_publisher_for_points_xyz_(false)
93 , use_latched_publisher_for_points_xyzrgba_(false)
94 , use_latched_publisher_for_color_image_(false)
95 , use_latched_publisher_for_depth_image_(false)
96 , use_latched_publisher_for_snr_image_(false)
97 , image_transport_(nh_)
100 ROS_INFO(
"Zivid ROS driver version %s", ZIVID_ROS_DRIVER_VERSION);
107 throw std::runtime_error(
"Zivid ROS driver started in the global namespace ('/')! This is unsupported. " 108 "Please specify namespace, e.g. using the ROS_NAMESPACE environment variable.");
111 ROS_INFO_STREAM(
"Built towards Zivid Core version " << ZIVID_CORE_VERSION);
112 ROS_INFO_STREAM(
"Running with Zivid Core version " << Zivid::Version::coreLibraryVersion());
113 if (Zivid::Version::coreLibraryVersion() != ZIVID_CORE_VERSION)
115 throw std::runtime_error(
"Zivid library mismatch! The running Zivid Core version does not match the " 116 "version this ROS driver was built towards. Hint: Try to clean and re-build your project " 120 std::string serial_number;
121 priv_.
param<decltype(serial_number)>(
"serial_number", serial_number,
"");
123 int max_capture_acquisitions;
124 priv_.
param<decltype(max_capture_acquisitions)>(
"max_capture_acquisitions", max_capture_acquisitions, 10);
128 std::string file_camera_path;
129 priv_.
param<decltype(file_camera_path)>(
"file_camera_path", file_camera_path,
"");
130 const bool file_camera_mode = !file_camera_path.empty();
138 if (file_camera_mode)
140 ROS_INFO(
"Creating file camera from file '%s'", file_camera_path.c_str());
145 auto cameras =
zivid_.cameras();
149 throw std::runtime_error(
"No cameras found. Ensure that the camera is connected to the USB3 port on your PC.");
151 else if (serial_number.empty())
154 ROS_INFO(
"Selecting first available camera");
155 for (
auto& c : cameras)
157 if (c.state().isAvailable())
160 throw std::runtime_error(
"No available cameras found. Is the camera in use by another process?");
165 if (serial_number.find(
":") == 0)
167 serial_number = serial_number.substr(1);
170 ROS_INFO(
"Searching for camera with serial number '%s' ...", serial_number.c_str());
171 for (
auto& c : cameras)
173 if (c.info().serialNumber() == Zivid::CameraInfo::SerialNumber(serial_number))
176 throw std::runtime_error(
"No camera found with serial number '" + serial_number +
"'");
180 if (!Zivid::Firmware::isUpToDate(
camera_))
182 ROS_INFO(
"The camera firmware is not up-to-date, starting update");
183 Zivid::Firmware::update(
camera_, [](
double progress,
const std::string& state) {
184 ROS_INFO(
" [%.0f%%] %s", progress, state.c_str());
186 ROS_INFO(
"Firmware update completed");
191 if (!file_camera_mode)
203 std::make_unique<Capture3DSettingsController>(
nh_,
camera_,
"settings", max_capture_acquisitions);
219 ROS_INFO(
"Advertising services");
230 ROS_INFO(
"Zivid camera driver is now ready!");
240 catch (
const std::exception& e)
242 ROS_INFO(
"%s failed with exception '%s'", __func__, e.what());
250 const auto state =
camera_.state();
251 if (state.isConnected().value())
261 auto cameras =
zivid_.cameras();
262 for (
auto& c : cameras)
264 if (
camera_.info().serialNumber() == c.info().serialNumber())
270 if (state.isAvailable().value())
273 <<
"' is not connected but is available. Re-connecting ...");
275 ROS_INFO(
"Successfully reconnected to camera!");
289 std::stringstream ss;
290 ss <<
"Camera status changed to " << toString(camera_status) <<
" (was " << toString(
camera_status_) <<
")";
304 zivid_camera::CameraInfoModelName::Response& res)
306 res.model_name =
camera_.info().modelName().toString();
311 zivid_camera::CameraInfoSerialNumber::Response& res)
313 res.serial_number =
camera_.info().serialNumber().toString();
325 if (settings.acquisitions().isEmpty())
327 throw std::runtime_error(
"capture called with 0 enabled acquisitions!");
330 ROS_INFO(
"Capturing with %zd acquisition(s)", settings.acquisitions().size());
344 if (settings2D.acquisitions().isEmpty())
346 throw std::runtime_error(
"capture_2d called with 0 enabled acquisitions!");
350 auto frame2D =
camera_.capture(settings2D);
354 auto image = frame2D.imageRGBA();
355 const auto intrinsics = Zivid::Experimental::Calibration::intrinsics(
camera_);
356 const auto camera_info =
makeCameraInfo(header, image.width(), image.height(), intrinsics);
363 CaptureAssistantSuggestSettings::Response&)
371 throw std::runtime_error(
"To use the CaptureAssistant the launch parameter 'max_capture_acquisitions' " 372 "must be at least 10, since the Capture Assistant may suggest up to 10 acquisitions. " 373 "See README.md for more information.");
376 using SuggestSettingsParameters = Zivid::CaptureAssistant::SuggestSettingsParameters;
378 const auto max_capture_time =
379 std::chrono::round<std::chrono::milliseconds>(std::chrono::duration<double>{ req.max_capture_time.toSec() });
380 const auto ambient_light_frequency = [&req]() {
381 switch (req.ambient_light_frequency)
383 case CaptureAssistantSuggestSettings::Request::AMBIENT_LIGHT_FREQUENCY_NONE:
384 return SuggestSettingsParameters::AmbientLightFrequency::none;
385 case CaptureAssistantSuggestSettings::Request::AMBIENT_LIGHT_FREQUENCY_50HZ:
386 return SuggestSettingsParameters::AmbientLightFrequency::hz50;
387 case CaptureAssistantSuggestSettings::Request::AMBIENT_LIGHT_FREQUENCY_60HZ:
388 return SuggestSettingsParameters::AmbientLightFrequency::hz60;
390 throw std::runtime_error(
"Unhandled AMBIENT_LIGHT_FREQUENCY value: " + std::to_string(req.ambient_light_frequency));
393 SuggestSettingsParameters suggest_settings_parameters{ SuggestSettingsParameters::MaxCaptureTime{ max_capture_time },
394 ambient_light_frequency };
395 ROS_INFO_STREAM(
"Getting suggested settings using parameters: " << suggest_settings_parameters);
396 const auto suggested_settings = Zivid::CaptureAssistant::suggestSettings(
camera_, suggest_settings_parameters);
397 ROS_INFO_STREAM(
"CaptureAssistant::suggestSettings returned " << suggested_settings.acquisitions().size()
409 throw std::runtime_error(
"Unable to capture since the camera is not connected. Please re-connect the camera and " 428 if (publish_points_xyz || publish_points_xyzrgba || publish_color_img || publish_depth_img || publish_snr_img)
431 auto point_cloud = frame.pointCloud();
434 const float scale = 0.001f;
435 const auto transformationMatrix = Zivid::Matrix4x4{ scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1 };
436 point_cloud.transform(transformationMatrix);
438 if (publish_points_xyz)
442 if (publish_points_xyzrgba)
446 if (publish_color_img || publish_depth_img || publish_snr_img)
448 const auto intrinsics = Zivid::Experimental::Calibration::intrinsics(
camera_);
449 const auto camera_info =
makeCameraInfo(header, point_cloud.width(), point_cloud.height(), intrinsics);
451 if (publish_color_img)
455 if (publish_depth_img)
494 std_msgs::Header header;
509 using ZividDataType = Zivid::PointXYZW;
510 auto msg = boost::make_shared<sensor_msgs::PointCloud2>();
511 fillCommonMsgFields(*msg, header, point_cloud.width(), point_cloud.height());
512 msg->fields.reserve(3);
513 msg->fields.push_back(createPointField(
"x", 0, sensor_msgs::PointField::FLOAT32, 1));
514 msg->fields.push_back(createPointField(
"y", 4, sensor_msgs::PointField::FLOAT32, 1));
515 msg->fields.push_back(createPointField(
"z", 8, sensor_msgs::PointField::FLOAT32, 1));
516 msg->is_dense =
false;
517 msg->point_step =
sizeof(ZividDataType);
518 msg->row_step = msg->point_step * msg->width;
519 msg->data.resize(msg->row_step * msg->height);
520 point_cloud.copyData<ZividDataType>(
reinterpret_cast<ZividDataType*
>(msg->data.data()));
528 auto msg = boost::make_shared<sensor_msgs::PointCloud2>();
529 fillCommonMsgFields(*msg, header, point_cloud.width(), point_cloud.height());
530 msg->fields.reserve(4);
531 msg->fields.push_back(createPointField(
"x", 0, sensor_msgs::PointField::FLOAT32, 1));
532 msg->fields.push_back(createPointField(
"y", 4, sensor_msgs::PointField::FLOAT32, 1));
533 msg->fields.push_back(createPointField(
"z", 8, sensor_msgs::PointField::FLOAT32, 1));
534 msg->fields.push_back(createPointField(
"rgba", 12, sensor_msgs::PointField::FLOAT32, 1));
535 msg->is_dense =
false;
539 using ZividDataType = Zivid::PointXYZColorBGRA;
540 msg->point_step =
sizeof(ZividDataType);
541 msg->row_step = msg->point_step * msg->width;
542 msg->data.resize(msg->row_step * msg->height);
543 point_cloud.copyData<ZividDataType>(
reinterpret_cast<ZividDataType*
>(msg->data.data()));
548 const Zivid::PointCloud& point_cloud)
556 const Zivid::Image<Zivid::ColorRGBA>& image)
561 const auto uint8_ptr_begin =
reinterpret_cast<const uint8_t*
>(image.data());
562 const auto uint8_ptr_end =
reinterpret_cast<const uint8_t*
>(image.data() + image.size());
563 msg->data = std::vector<uint8_t>(uint8_ptr_begin, uint8_ptr_end);
568 const Zivid::PointCloud& point_cloud)
576 const Zivid::PointCloud& point_cloud)
585 const Zivid::CameraIntrinsics& intrinsics)
587 auto msg = boost::make_shared<sensor_msgs::CameraInfo>();
588 msg->header = header;
589 msg->width =
static_cast<uint32_t
>(width);
590 msg->height =
static_cast<uint32_t
>(height);
594 const auto distortion = intrinsics.distortion();
596 msg->D[0] = distortion.k1().value();
597 msg->D[1] = distortion.k2().value();
598 msg->D[2] = distortion.p1().value();
599 msg->D[3] = distortion.p2().value();
600 msg->D[4] = distortion.k3().value();
606 const auto camera_matrix = intrinsics.cameraMatrix();
607 msg->K[0] = camera_matrix.fx().value();
608 msg->K[2] = camera_matrix.cx().value();
609 msg->K[4] = camera_matrix.fy().value();
610 msg->K[5] = camera_matrix.cy().value();
622 msg->P[0] = camera_matrix.fx().value();
623 msg->P[2] = camera_matrix.cx().value();
624 msg->P[5] = camera_matrix.fy().value();
625 msg->P[6] = camera_matrix.cy().value();
void publish(const sensor_msgs::Image &image, const sensor_msgs::CameraInfo &info) const
std::unique_ptr< Capture2DSettingsController > capture_2d_settings_controller_
void publish(const boost::shared_ptr< M > &message) const
void publishSnrImage(const std_msgs::Header &header, const sensor_msgs::CameraInfoConstPtr &camera_info, const Zivid::PointCloud &point_cloud)
bool use_latched_publisher_for_color_image_
bool captureServiceHandler(Capture::Request &req, Capture::Response &res)
image_transport::ImageTransport image_transport_
uint32_t getNumSubscribers() const
bool shouldPublishSnrImg() const
CameraStatus camera_status_
ros::ServiceServer is_connected_service_
bool captureAssistantSuggestSettingsServiceHandler(CaptureAssistantSuggestSettings::Request &req, CaptureAssistantSuggestSettings::Response &res)
bool capture2DServiceHandler(Capture2D::Request &req, Capture2D::Response &res)
bool shouldPublishPointsXYZ() const
ros::ServiceServer capture_assistant_suggest_settings_service_
void publishColorImage(const std_msgs::Header &header, const sensor_msgs::CameraInfoConstPtr &camera_info, const Zivid::PointCloud &point_cloud)
image_transport::CameraPublisher snr_image_publisher_
void publishDepthImage(const std_msgs::Header &header, const sensor_msgs::CameraInfoConstPtr &camera_info, const Zivid::PointCloud &point_cloud)
void reconnectToCameraIfNecessary()
CameraPublisher advertiseCamera(const std::string &base_topic, uint32_t queue_size, bool latch=false)
bool use_latched_publisher_for_depth_image_
ROSCPP_DECL const std::string & getNamespace()
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
bool use_latched_publisher_for_points_xyz_
const std::string TYPE_32FC1
const std::string PLUMB_BOB
ros::Publisher points_xyz_publisher_
Zivid::Application zivid_
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
const std::string & getNamespace() const
bool use_latched_publisher_for_points_xyzrgba_
void publishPointCloudXYZRGBA(const std_msgs::Header &header, const Zivid::PointCloud &point_cloud)
ros::ServiceServer capture_2d_service_
#define ROS_WARN_STREAM(args)
ros::ServiceServer capture_service_
#define ROS_DEBUG_STREAM(args)
void setCameraStatus(CameraStatus camera_status)
bool shouldPublishColorImg() const
sensor_msgs::CameraInfoConstPtr makeCameraInfo(const std_msgs::Header &header, std::size_t width, std::size_t height, const Zivid::CameraIntrinsics &intrinsics)
image_transport::CameraPublisher depth_image_publisher_
ZividCamera(ros::NodeHandle &nh, ros::NodeHandle &priv)
bool cameraInfoModelNameServiceHandler(CameraInfoModelName::Request &req, CameraInfoModelName::Response &res)
bool isConnectedServiceHandler(IsConnected::Request &req, IsConnected::Response &res)
uint32_t getNumSubscribers() const
static int numChannels(const std::string &encoding)
std::unique_ptr< Capture3DSettingsController > capture_settings_controller_
#define ROS_INFO_STREAM(args)
void publishPointCloudXYZ(const std_msgs::Header &header, const Zivid::PointCloud &point_cloud)
ros::ServiceServer camera_info_model_name_service_
ros::Timer camera_connection_keepalive_timer_
bool use_latched_publisher_for_snr_image_
void publishFrame(Zivid::Frame &&frame)
static int bitDepth(const std::string &encoding)
ros::ServiceServer camera_info_serial_number_service_
std_msgs::Header makeHeader()
void onCameraConnectionKeepAliveTimeout(const ros::TimerEvent &event)
ros::Publisher points_xyzrgba_publisher_
bool cameraInfoSerialNumberServiceHandler(CameraInfoSerialNumber::Request &req, CameraInfoSerialNumber::Response &res)
bool shouldPublishDepthImg() const
void serviceHandlerHandleCameraConnectionLoss()
bool shouldPublishPointsXYZRGBA() const
image_transport::CameraPublisher color_image_publisher_