33 #include <opencv2/imgproc/types_c.h>
35 #ifdef RTABMAP_REALSENSE2
36 #include <librealsense2/rsutil.h>
37 #include <librealsense2/hpp/rs_processing.hpp>
38 #include <librealsense2/rs_advanced_mode.hpp>
47 #ifdef RTABMAP_REALSENSE2
55 const std::string &
device,
58 Camera(imageRate, localTransform)
59 #ifdef RTABMAP_REALSENSE2
62 depth_scale_meters_(1.0
f),
64 clockSyncWarningShown_(
false),
65 imuGlobalSyncWarningShown_(
false),
66 emitterEnabled_(
true),
70 odometryProvided_(
false),
71 odometryImagesDisabled_(
false),
72 odometryOnlyLeftStream_(
false),
76 cameraDepthWidth_(640),
77 cameraDepthHeight_(480),
79 globalTimeSync_(
true),
89 #ifdef RTABMAP_REALSENSE2
94 #ifdef RTABMAP_REALSENSE2
95 void CameraRealSense2::close()
100 UDEBUG(
"Closing device(s)...");
101 for(
size_t i=0;
i<dev_.size(); ++
i)
103 UDEBUG(
"Closing %d sensor(s) from device %d...", (
int)dev_[i].query_sensors().
size(), (
int)i);
104 for(rs2::sensor _sensor : dev_[i].query_sensors())
106 if(!_sensor.get_active_streams().empty())
113 catch(
const rs2::error & error)
120 dev_[
i].hardware_reset();
124 UDEBUG(
"Clearing devices...");
127 catch(
const rs2::error & error)
135 void CameraRealSense2::imu_callback(rs2::frame frame)
137 auto stream = frame.get_profile().stream_type();
138 cv::Vec3f crnt_reading = *
reinterpret_cast<const cv::Vec3f*
>(frame.get_data());
146 if(stream == RS2_STREAM_GYRO)
148 gyroBuffer_.insert(gyroBuffer_.end(), std::make_pair(frame.get_timestamp(), crnt_reading));
149 if(gyroBuffer_.size() > 1000)
151 gyroBuffer_.erase(gyroBuffer_.begin());
156 accBuffer_.insert(accBuffer_.end(), std::make_pair(frame.get_timestamp(), crnt_reading));
157 if(accBuffer_.size() > 1000)
159 accBuffer_.erase(accBuffer_.begin());
165 Transform CameraRealSense2::realsense2PoseRotation_ = Transform(
170 void CameraRealSense2::pose_callback(rs2::frame frame)
172 rs2_pose pose = frame.as<rs2::pose_frame>().get_pose_data();
174 Transform poseT = Transform(
186 poseBuffer_.insert(poseBuffer_.end(), std::make_pair(frame.get_timestamp(), std::make_pair(poseT, pose.tracker_confidence)));
187 if(poseBuffer_.size() > 1000)
189 poseBuffer_.erase(poseBuffer_.begin());
193 void CameraRealSense2::frame_callback(rs2::frame frame)
198 void CameraRealSense2::multiple_message_callback(rs2::frame frame)
204 auto stream = frame.get_profile().stream_type();
207 case RS2_STREAM_GYRO:
208 case RS2_STREAM_ACCEL:
212 case RS2_STREAM_POSE:
214 if(odometryProvided_)
216 pose_callback(frame);
221 frame_callback(frame);
225 void CameraRealSense2::getPoseAndIMU(
226 const double & stamp,
228 unsigned int & poseConfidence,
237 if(!poseBuffer_.empty())
241 while(maxWaitTimeMs>0 && poseBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
248 if(poseBuffer_.rbegin()->first < stamp)
250 if(maxWaitTimeMs > 0)
252 UWARN(
"Could not find poses to interpolate at image time %f after waiting %d ms (last is %f)...", stamp/1000.0, maxWaitTimeMs, poseBuffer_.rbegin()->first/1000.0);
257 std::map<double, std::pair<Transform, unsigned int> >::const_iterator iterB = poseBuffer_.lower_bound(stamp);
258 std::map<double, std::pair<Transform, unsigned int> >::const_iterator iterA = iterB;
259 if(iterA != poseBuffer_.begin())
263 if(iterB == poseBuffer_.end())
267 if(iterA == iterB && stamp == iterA->first)
269 pose = iterA->second.first;
270 poseConfidence = iterA->second.second;
272 else if(stamp >= iterA->first && stamp <= iterB->first)
274 pose = iterA->second.first.interpolate((stamp-iterA->first) / (iterB->first-iterA->first), iterB->second.first);
275 poseConfidence = iterA->second.second;
279 if(!imuGlobalSyncWarningShown_)
281 if(stamp < iterA->first)
283 UWARN(
"Could not find pose data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0);
287 UWARN(
"Could not find pose data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0, iterB->first/1000.0);
292 if(!imuGlobalSyncWarningShown_)
294 UWARN(
"As globalTimeSync option is off, the received pose, gyro and accelerometer will be re-stamped with image time. This message is only shown once.");
295 imuGlobalSyncWarningShown_ =
true;
297 std::map<double, std::pair<Transform, unsigned int> >::const_reverse_iterator iterC = poseBuffer_.rbegin();
298 pose = iterC->second.first;
299 poseConfidence = iterC->second.second;
306 if(accBuffer_.empty() || gyroBuffer_.empty())
318 while(maxWaitTimeMs > 0 && accBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
326 if(globalTimeSync_ && accBuffer_.rbegin()->first < stamp)
330 UWARN(
"Could not find acc data to interpolate at image time %f after waiting %d ms (last is %f)...", stamp/1000.0, maxWaitTimeMs, accBuffer_.rbegin()->first/1000.0);
337 std::map<double, cv::Vec3f>::const_iterator iterB = accBuffer_.lower_bound(stamp);
338 std::map<double, cv::Vec3f>::const_iterator iterA = iterB;
339 if(iterA != accBuffer_.begin())
343 if(iterB == accBuffer_.end())
347 if(iterA == iterB && stamp == iterA->first)
349 acc[0] = iterA->second[0];
350 acc[1] = iterA->second[1];
351 acc[2] = iterA->second[2];
353 else if(stamp >= iterA->first && stamp <= iterB->first)
355 float t = (stamp-iterA->first) / (iterB->first-iterA->first);
356 acc[0] = iterA->second[0] +
t*(iterB->second[0] - iterA->second[0]);
357 acc[1] = iterA->second[1] +
t*(iterB->second[1] - iterA->second[1]);
358 acc[2] = iterA->second[2] +
t*(iterB->second[2] - iterA->second[2]);
362 if(!imuGlobalSyncWarningShown_)
364 if(stamp < iterA->first)
366 UWARN(
"Could not find acc data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0);
370 UWARN(
"Could not find acc data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0, iterB->first/1000.0);
375 if(!imuGlobalSyncWarningShown_)
377 UWARN(
"As globalTimeSync option is off, the received gyro and accelerometer will be re-stamped with image time. This message is only shown once.");
378 imuGlobalSyncWarningShown_ =
true;
380 std::map<double, cv::Vec3f>::const_reverse_iterator iterC = accBuffer_.rbegin();
381 acc[0] = iterC->second[0];
382 acc[1] = iterC->second[1];
383 acc[2] = iterC->second[2];
402 while(maxWaitTimeMs>0 && gyroBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
410 if(globalTimeSync_ && gyroBuffer_.rbegin()->first < stamp)
414 UWARN(
"Could not find gyro data to interpolate at image time %f after waiting %d ms (last is %f)...", stamp/1000.0, maxWaitTimeMs, gyroBuffer_.rbegin()->first/1000.0);
421 std::map<double, cv::Vec3f>::const_iterator iterB = gyroBuffer_.lower_bound(stamp);
422 std::map<double, cv::Vec3f>::const_iterator iterA = iterB;
423 if(iterA != gyroBuffer_.begin())
427 if(iterB == gyroBuffer_.end())
431 if(iterA == iterB && stamp == iterA->first)
433 gyro[0] = iterA->second[0];
434 gyro[1] = iterA->second[1];
435 gyro[2] = iterA->second[2];
437 else if(stamp >= iterA->first && stamp <= iterB->first)
439 float t = (stamp-iterA->first) / (iterB->first-iterA->first);
440 gyro[0] = iterA->second[0] +
t*(iterB->second[0] - iterA->second[0]);
441 gyro[1] = iterA->second[1] +
t*(iterB->second[1] - iterA->second[1]);
442 gyro[2] = iterA->second[2] +
t*(iterB->second[2] - iterA->second[2]);
446 if(!imuGlobalSyncWarningShown_)
448 if(stamp < iterA->first)
450 UWARN(
"Could not find gyro data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0);
454 UWARN(
"Could not find gyro data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp/1000.0, iterA->first/1000.0, iterB->first/1000.0);
459 if(!imuGlobalSyncWarningShown_)
461 UWARN(
"As globalTimeSync option is off, the latest received gyro and accelerometer will be re-stamped with image time. This message is only shown once.");
462 imuGlobalSyncWarningShown_ =
true;
464 std::map<double, cv::Vec3f>::const_reverse_iterator iterC = gyroBuffer_.rbegin();
465 gyro[0] = iterC->second[0];
466 gyro[1] = iterC->second[1];
467 gyro[2] = iterC->second[2];
479 imu = IMU(gyro, cv::Mat::eye(3, 3, CV_64FC1), acc, cv::Mat::eye(3, 3, CV_64FC1), imuLocalTransform_);
486 #ifdef RTABMAP_REALSENSE2
488 UINFO(
"setupDevice...");
492 clockSyncWarningShown_ =
false;
493 imuGlobalSyncWarningShown_ =
false;
495 rs2::device_list
list = ctx_.query_devices();
498 UERROR(
"No RealSense2 devices were found!");
507 auto sn = dev.get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
508 auto pid_str = dev.get_info(RS2_CAMERA_INFO_PRODUCT_ID);
509 auto name = dev.get_info(RS2_CAMERA_INFO_NAME);
512 std::stringstream ss;
513 ss << std::hex << pid_str;
515 UINFO(
"Device \"%s\" with serial number %s was found with product ID=%d.",
name, sn, (
int)pid);
516 if(dualMode_ && pid == 0x0B37)
534 catch(
const rs2::error &
error)
536 UWARN(
"%s. Is the camera already used with another app?",
error.what());
541 if(dualMode_ && dev_.size()==2)
543 UERROR(
"Dual setup is enabled, but a D400 camera is not detected!");
548 UERROR(
"The requested device \"%s\" is NOT found!", deviceId_.c_str());
552 else if(dualMode_ && dev_.size()!=2)
554 UERROR(
"Dual setup is enabled, but a T265 camera is not detected!");
561 if (!jsonConfig_.empty())
563 if (dev_[0].is<rs400::advanced_mode>())
565 std::stringstream ss;
566 std::ifstream in(jsonConfig_);
570 std::string json_file_content = ss.str();
572 auto adv = dev_[0].as<rs400::advanced_mode>();
573 adv.load_json(json_file_content);
574 UINFO(
"JSON file is loaded! (%s)", jsonConfig_.c_str());
578 UWARN(
"JSON file provided doesn't exist! (%s)", jsonConfig_.c_str());
583 UWARN(
"A json config file is provided (%s), but device does not support advanced settings!", jsonConfig_.c_str());
587 ctx_.set_devices_changed_callback([
this](rs2::event_information&
info)
589 for(
size_t i=0;
i<dev_.size(); ++
i)
591 if (
info.was_removed(dev_[
i]))
595 UDEBUG(
"The device %d has been disconnected!", i);
599 UERROR(
"The device %d has been disconnected!", i);
605 auto sn = dev_[0].get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
606 UINFO(
"Using device with Serial No: %s", sn);
608 auto camera_name = dev_[0].get_info(RS2_CAMERA_INFO_NAME);
609 UINFO(
"Device Name: %s", camera_name);
611 auto fw_ver = dev_[0].get_info(RS2_CAMERA_INFO_FIRMWARE_VERSION);
612 UINFO(
"Device FW version: %s", fw_ver);
614 auto pid = dev_[0].get_info(RS2_CAMERA_INFO_PRODUCT_ID);
615 UINFO(
"Device Product ID: 0x%s", pid);
617 auto dev_sensors = dev_[0].query_sensors();
621 auto dev_sensors2 = dev_[1].query_sensors();
622 dev_sensors.insert(dev_sensors.end(), dev_sensors2.begin(), dev_sensors2.end());
625 UINFO(
"Device Sensors: ");
626 std::vector<rs2::sensor> sensors(2);
629 for(
auto&& elem : dev_sensors)
631 std::string
module_name = elem.get_info(RS2_CAMERA_INFO_NAME);
632 if (
"Stereo Module" == module_name)
635 sensors[1].set_option(rs2_option::RS2_OPTION_EMITTER_ENABLED, emitterEnabled_);
637 else if (
"Coded-Light Depth Sensor" == module_name)
640 else if (
"RGB Camera" == module_name)
647 else if (
"Wide FOV Camera" == module_name)
650 else if (
"Motion Module" == module_name)
658 else if (
"Tracking Module" == module_name)
669 sensors.back() = elem;
670 sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_POSE_JUMPING, 0);
671 sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_RELOCALIZATION, 0);
673 else if (
"L500 Depth Sensor" == module_name)
679 cameraWidth_ = cameraDepthWidth_;
680 cameraHeight_ = cameraDepthHeight_;
681 cameraFps_ = cameraDepthFps_;
690 UINFO(
"%s was found.", elem.get_info(RS2_CAMERA_INFO_NAME));
695 model_ = CameraModel();
696 std::vector<std::vector<rs2::stream_profile> > profilesPerSensor(sensors.size());
697 for (
unsigned int i=0;
i<sensors.size(); ++
i)
699 if(i==0 && ir_ && !stereo)
703 UINFO(
"Sensor %d \"%s\"", (
int)i, sensors[i].get_info(RS2_CAMERA_INFO_NAME));
704 auto profiles = sensors[
i].get_stream_profiles();
706 UINFO(
"profiles=%d", (
int)profiles.size());
711 auto video_profile =
profile.as<rs2::video_stream_profile>();
712 UINFO(
"%s %d %d %d %d %s type=%d", rs2_format_to_string(
713 video_profile.format()),
714 video_profile.width(),
715 video_profile.height(),
717 video_profile.stream_index(),
718 video_profile.stream_name().c_str(),
719 video_profile.stream_type());
725 auto video_profile =
profile.as<rs2::video_stream_profile>();
728 if( (video_profile.width() == cameraWidth_ &&
729 video_profile.height() == cameraHeight_ &&
730 video_profile.fps() == cameraFps_) ||
731 (strcmp(sensors[i].get_info(RS2_CAMERA_INFO_NAME),
"L500 Depth Sensor")==0 &&
732 video_profile.width() == cameraDepthWidth_ &&
733 video_profile.height() == cameraDepthHeight_ &&
734 video_profile.fps() == cameraDepthFps_))
736 auto intrinsic = video_profile.get_intrinsics();
739 if((!ir_ && video_profile.format() == RS2_FORMAT_RGB8 && video_profile.stream_type() == RS2_STREAM_COLOR) ||
740 (ir_ && video_profile.format() == RS2_FORMAT_Y8 && (video_profile.stream_index() == 1 || isL500)))
742 if(!profilesPerSensor[i].
empty())
745 profilesPerSensor[
i].push_back(profilesPerSensor[i].back());
746 profilesPerSensor[
i].front() =
profile;
750 profilesPerSensor[
i].push_back(
profile);
752 rgbBuffer_ = cv::Mat(cv::Size(cameraWidth_, cameraHeight_), video_profile.format() == RS2_FORMAT_Y8?CV_8UC1:CV_8UC3, ir_?cv::Scalar(0):cv::Scalar(0, 0, 0));
753 model_ = CameraModel(camera_name, intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
this->getLocalTransform(), 0, cv::Size(intrinsic.width, intrinsic.height));
754 UINFO(
"Model: %dx%d fx=%f fy=%f cx=%f cy=%f dist model=%d coeff=%f %f %f %f %f",
755 intrinsic.width, intrinsic.height,
756 intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
758 intrinsic.coeffs[0], intrinsic.coeffs[1], intrinsic.coeffs[2], intrinsic.coeffs[3], intrinsic.coeffs[4]);
760 if(video_profile.format() == RS2_FORMAT_RGB8 || profilesPerSensor[i].size()==2)
766 else if(((!ir_ || irDepth_) && video_profile.format() == RS2_FORMAT_Z16) ||
767 (ir_ && !irDepth_ && video_profile.format() == RS2_FORMAT_Y8 && video_profile.stream_index() == 2))
769 profilesPerSensor[
i].push_back(
profile);
770 depthBuffer_ = cv::Mat(cv::Size(cameraWidth_, cameraHeight_), video_profile.format() == RS2_FORMAT_Y8?CV_8UC1:CV_16UC1, cv::Scalar(0));
772 if(!ir_ || irDepth_ || profilesPerSensor[i].
size()==2)
778 else if(video_profile.format() == RS2_FORMAT_MOTION_XYZ32F || video_profile.format() == RS2_FORMAT_6DOF)
789 bool modified =
false;
790 for (
size_t j= 0;
j < profilesPerSensor[
i].size(); ++
j)
792 if (profilesPerSensor[i][j].stream_type() ==
profile.stream_type())
794 if (
profile.stream_type() == RS2_STREAM_ACCEL)
796 if(
profile.fps() > profilesPerSensor[i][j].fps())
800 else if (
profile.stream_type() == RS2_STREAM_GYRO)
802 if(
profile.fps() < profilesPerSensor[i][j].fps())
809 profilesPerSensor[
i].push_back(
profile);
813 else if(stereo || dualMode_)
817 video_profile.format() == RS2_FORMAT_Y8 &&
818 video_profile.width() == 848 &&
819 video_profile.height() == 800 &&
820 video_profile.fps() == 30)
823 profilesPerSensor[
i].push_back(
profile);
827 rgbBuffer_ = cv::Mat(cv::Size(848, 800), CV_8UC1, cv::Scalar(0));
828 if(odometryOnlyLeftStream_)
830 auto intrinsic = video_profile.get_intrinsics();
831 UINFO(
"Model: %dx%d fx=%f fy=%f cx=%f cy=%f dist model=%d coeff=%f %f %f %f",
832 intrinsic.width, intrinsic.height,
833 intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
835 intrinsic.coeffs[0], intrinsic.coeffs[1], intrinsic.coeffs[2], intrinsic.coeffs[3]);
836 cv::Mat
K = cv::Mat::eye(3,3,CV_64FC1);
837 K.at<
double>(0,0) = intrinsic.fx;
838 K.at<
double>(1,1) = intrinsic.fy;
839 K.at<
double>(0,2) = intrinsic.ppx;
840 K.at<
double>(1,2) = intrinsic.ppy;
841 UASSERT(intrinsic.model == RS2_DISTORTION_KANNALA_BRANDT4);
842 cv::Mat
D = cv::Mat::zeros(1,6,CV_64FC1);
843 D.at<
double>(0,0) = intrinsic.coeffs[0];
844 D.at<
double>(0,1) = intrinsic.coeffs[1];
845 D.at<
double>(0,4) = intrinsic.coeffs[2];
846 D.at<
double>(0,5) = intrinsic.coeffs[3];
847 cv::Mat
P = cv::Mat::eye(3, 4, CV_64FC1);
848 P.at<
double>(0,0) = intrinsic.fx;
849 P.at<
double>(1,1) = intrinsic.fy;
850 P.at<
double>(0,2) = intrinsic.ppx;
851 P.at<
double>(1,2) = intrinsic.ppy;
852 cv::Mat
R = cv::Mat::eye(3, 3, CV_64FC1);
853 model_ = CameraModel(camera_name, cv::Size(intrinsic.width, intrinsic.height), K, D, R,
P,
this->getLocalTransform());
855 model_.initRectificationMap();
858 else if(!odometryOnlyLeftStream_)
861 depthBuffer_ = cv::Mat(cv::Size(848, 800), CV_8UC1, cv::Scalar(0));
865 else if(video_profile.format() == RS2_FORMAT_MOTION_XYZ32F || video_profile.format() == RS2_FORMAT_6DOF)
870 profilesPerSensor[
i].push_back(
profile);
878 UERROR(
"Given stream configuration is not supported by the device! "
879 "Stream Index: %d, Width: %d, Height: %d, FPS: %d", i, cameraWidth_, cameraHeight_, cameraFps_);
880 UERROR(
"Available configurations:");
883 auto video_profile =
profile.as<rs2::video_stream_profile>();
884 UERROR(
"%s %d %d %d %d %s type=%d", rs2_format_to_string(
885 video_profile.format()),
886 video_profile.width(),
887 video_profile.height(),
889 video_profile.stream_index(),
890 video_profile.stream_name().c_str(),
891 video_profile.stream_type());
899 if(!model_.isValidForProjection())
901 UERROR(
"Calibration info not valid!");
902 std::cout<< model_ << std::endl;
908 UINFO(
"Set base to pose");
910 UINFO(
"dualExtrinsics_ = %s", dualExtrinsics_.prettyPrint().c_str());
911 Transform baseToCam = this->getLocalTransform()*dualExtrinsics_;
912 UASSERT(profilesPerSensor.size()>=2);
913 UASSERT(profilesPerSensor.back().size() == 3);
914 rs2_extrinsics poseToIMU = profilesPerSensor.back()[0].get_extrinsics_to(profilesPerSensor.back()[2]);
916 Transform poseToIMUT(
917 poseToIMU.rotation[0], poseToIMU.rotation[1], poseToIMU.rotation[2], poseToIMU.translation[0],
918 poseToIMU.rotation[3], poseToIMU.rotation[4], poseToIMU.rotation[5], poseToIMU.translation[1],
919 poseToIMU.rotation[6], poseToIMU.rotation[7], poseToIMU.rotation[8], poseToIMU.translation[2]);
920 poseToIMUT = realsense2PoseRotation_ * poseToIMUT;
921 UINFO(
"poseToIMU = %s", poseToIMUT.prettyPrint().c_str());
923 UINFO(
"BaseToCam = %s", baseToCam.prettyPrint().c_str());
924 model_.setLocalTransform(baseToCam);
925 imuLocalTransform_ = this->getLocalTransform() * poseToIMUT;
928 if(ir_ && !irDepth_ && profilesPerSensor.size() >= 2 && profilesPerSensor[1].size() >= 2)
930 rs2_extrinsics leftToRight = profilesPerSensor[1][1].get_extrinsics_to(profilesPerSensor[1][0]);
931 Transform leftToRightT(
932 leftToRight.rotation[0], leftToRight.rotation[1], leftToRight.rotation[2], leftToRight.translation[0],
933 leftToRight.rotation[3], leftToRight.rotation[4], leftToRight.rotation[5], leftToRight.translation[1],
934 leftToRight.rotation[6], leftToRight.rotation[7], leftToRight.rotation[8], leftToRight.translation[2]);
936 UINFO(
"left to right transform = %s", leftToRightT.prettyPrint().c_str());
939 stereoModel_ = StereoCameraModel(model_.fx(), model_.fy(), model_.cx(), model_.cy(), leftToRightT.x(), model_.localTransform(), model_.imageSize());
940 UINFO(
"Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
941 stereoModel_.left().fx(),
942 stereoModel_.left().cx(),
943 stereoModel_.left().cy(),
944 stereoModel_.baseline());
947 if(!dualMode_ && profilesPerSensor.size() == 3)
949 if(!profilesPerSensor[2].
empty() && !profilesPerSensor[0].
empty())
951 rs2_extrinsics leftToIMU = profilesPerSensor[2][0].get_extrinsics_to(profilesPerSensor[0][0]);
952 Transform leftToIMUT(
953 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
954 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
955 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
956 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
957 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
959 else if(!profilesPerSensor[2].
empty() && !profilesPerSensor[1].
empty())
961 rs2_extrinsics leftToIMU = profilesPerSensor[2][0].get_extrinsics_to(profilesPerSensor[1][0]);
962 Transform leftToIMUT(
963 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
964 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
965 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
967 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
968 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
976 std::string serial = sn;
977 if(!cameraName.empty())
981 if(!odometryImagesDisabled_ &&
982 !odometryOnlyLeftStream_ &&
983 !calibrationFolder.empty() && !serial.empty())
985 if(!stereoModel_.load(calibrationFolder, serial,
false))
987 UWARN(
"Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
988 serial.c_str(), calibrationFolder.c_str());
992 UINFO(
"Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
993 stereoModel_.left().fx(),
994 stereoModel_.left().cx(),
995 stereoModel_.left().cy(),
996 stereoModel_.baseline());
1007 if(odometryProvided_)
1009 rs2_extrinsics poseToLeft = profilesPerSensor[0][0].get_extrinsics_to(profilesPerSensor[0][4]);
1010 rs2_extrinsics poseToIMU = profilesPerSensor[0][2].get_extrinsics_to(profilesPerSensor[0][4]);
1011 Transform poseToLeftT(
1012 poseToLeft.rotation[0], poseToLeft.rotation[1], poseToLeft.rotation[2], poseToLeft.translation[0],
1013 poseToLeft.rotation[3], poseToLeft.rotation[4], poseToLeft.rotation[5], poseToLeft.translation[1],
1014 poseToLeft.rotation[6], poseToLeft.rotation[7], poseToLeft.rotation[8], poseToLeft.translation[2]);
1015 poseToLeftT = realsense2PoseRotation_ * poseToLeftT;
1016 UINFO(
"poseToLeft = %s", poseToLeftT.prettyPrint().c_str());
1018 Transform poseToIMUT(
1019 poseToIMU.rotation[0], poseToIMU.rotation[1], poseToIMU.rotation[2], poseToIMU.translation[0],
1020 poseToIMU.rotation[3], poseToIMU.rotation[4], poseToIMU.rotation[5], poseToIMU.translation[1],
1021 poseToIMU.rotation[6], poseToIMU.rotation[7], poseToIMU.rotation[8], poseToIMU.translation[2]);
1022 poseToIMUT = realsense2PoseRotation_ * poseToIMUT;
1023 UINFO(
"poseToIMU = %s", poseToIMUT.prettyPrint().c_str());
1025 Transform opticalTransform(0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0);
1026 this->setLocalTransform(this->getLocalTransform() * opticalTransform.inverse());
1027 if(odometryOnlyLeftStream_)
1028 model_.setLocalTransform(this->getLocalTransform()*poseToLeftT);
1030 stereoModel_.setLocalTransform(this->getLocalTransform()*poseToLeftT);
1031 imuLocalTransform_ = this->getLocalTransform()* poseToIMUT;
1033 if(odometryImagesDisabled_)
1036 std::vector<rs2::stream_profile> profiles;
1037 profiles.push_back(profilesPerSensor[0][4]);
1038 profilesPerSensor[0] = profiles;
1044 rs2_extrinsics leftToIMU = profilesPerSensor[0][2].get_extrinsics_to(profilesPerSensor[0][0]);
1045 Transform leftToIMUT(
1046 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
1047 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
1048 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
1049 UINFO(
"leftToIMU = %s", leftToIMUT.prettyPrint().c_str());
1050 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
1051 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
1052 if(odometryOnlyLeftStream_)
1053 model_.setLocalTransform(this->getLocalTransform());
1055 stereoModel_.setLocalTransform(this->getLocalTransform());
1057 if(!odometryImagesDisabled_ && rectifyImages_ && !model_.isValidForRectification() && !stereoModel_.isValidForRectification())
1059 UERROR(
"Parameter \"rectifyImages\" is set, but no stereo model is loaded or valid.");
1064 std::function<void(rs2::frame)> multiple_message_callback_function = [
this](rs2::frame frame){multiple_message_callback(frame);};
1066 for (
unsigned int i=0;
i<sensors.size(); ++
i)
1068 if(profilesPerSensor[i].
size())
1070 UINFO(
"Starting sensor %d with %d profiles", (
int)i, (
int)profilesPerSensor[i].
size());
1071 for (
size_t j = 0;
j < profilesPerSensor[
i].size(); ++
j)
1073 auto video_profile = profilesPerSensor[
i][
j].as<rs2::video_stream_profile>();
1074 UINFO(
"Opening: %s %d %d %d %d %s type=%d", rs2_format_to_string(
1075 video_profile.format()),
1076 video_profile.width(),
1077 video_profile.height(),
1078 video_profile.fps(),
1079 video_profile.stream_index(),
1080 video_profile.stream_name().c_str(),
1081 video_profile.stream_type());
1083 if(globalTimeSync_ && sensors[i].supports(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED))
1085 float value = sensors[
i].get_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED);
1086 UINFO(
"Set RS2_OPTION_GLOBAL_TIME_ENABLED=1 (was %f) for sensor %d", value, (
int)i);
1087 sensors[
i].set_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED, 1);
1089 sensors[
i].open(profilesPerSensor[i]);
1090 if(sensors[i].is<rs2::depth_sensor>())
1092 auto depth_sensor = sensors[
i].as<rs2::depth_sensor>();
1093 depth_scale_meters_ = depth_sensor.get_depth_scale();
1094 UINFO(
"Depth scale %f for sensor %d", depth_scale_meters_, (
int)i);
1096 sensors[
i].start(multiple_message_callback_function);
1101 UINFO(
"Enabling streams...done!");
1106 UERROR(
"CameraRealSense: RTAB-Map is not built with RealSense2 support!");
1111 bool CameraRealSense2::isCalibrated()
const
1113 #ifdef RTABMAP_REALSENSE2
1114 return model_.isValidForProjection() || stereoModel_.isValidForRectification();
1120 std::string CameraRealSense2::getSerial()
const
1122 #ifdef RTABMAP_REALSENSE2
1125 return dev_[0].get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
1131 bool CameraRealSense2::odomProvided()
const
1133 #ifdef RTABMAP_REALSENSE2
1134 return odometryProvided_;
1140 bool CameraRealSense2::getPose(
double stamp,
Transform & pose, cv::Mat & covariance,
double maxWaitTime)
1142 #ifdef RTABMAP_REALSENSE2
1144 unsigned int confidence = 0;
1145 double rsStamp = stamp*1000.0;
1147 getPoseAndIMU(rsStamp,
p, confidence, imu, maxWaitTime*1000);
1152 pose = this->getLocalTransform() *
p * this->getLocalTransform().inverse();
1154 covariance = cv::Mat::eye(6,6,CV_64FC1) * 0.0001;
1155 covariance.rowRange(0,3) *=
pow(10, 3-(
int)confidence);
1156 covariance.rowRange(3,6) *=
pow(10, 1-(
int)confidence);
1163 void CameraRealSense2::setEmitterEnabled(
bool enabled)
1165 #ifdef RTABMAP_REALSENSE2
1166 emitterEnabled_ = enabled;
1170 void CameraRealSense2::setIRFormat(
bool enabled,
bool useDepthInsteadOfRightImage)
1172 #ifdef RTABMAP_REALSENSE2
1174 irDepth_ = useDepthInsteadOfRightImage;
1178 void CameraRealSense2::setResolution(
int width,
int height,
int fps)
1180 #ifdef RTABMAP_REALSENSE2
1181 cameraWidth_ = width;
1182 cameraHeight_ = height;
1187 void CameraRealSense2::setDepthResolution(
int width,
int height,
int fps)
1189 #ifdef RTABMAP_REALSENSE2
1190 cameraDepthWidth_ = width;
1191 cameraDepthHeight_ = height;
1192 cameraDepthFps_ = fps;
1196 void CameraRealSense2::setGlobalTimeSync(
bool enabled)
1198 #ifdef RTABMAP_REALSENSE2
1199 globalTimeSync_ = enabled;
1203 void CameraRealSense2::setDualMode(
bool enabled,
const Transform & extrinsics)
1205 #ifdef RTABMAP_REALSENSE2
1207 dualMode_ = enabled;
1208 dualExtrinsics_ = extrinsics*CameraModel::opticalRotation();
1211 odometryProvided_ =
true;
1212 odometryImagesDisabled_ =
false;
1213 odometryOnlyLeftStream_ =
false;
1218 void CameraRealSense2::setJsonConfig(
const std::string & json)
1220 #ifdef RTABMAP_REALSENSE2
1225 void CameraRealSense2::setImagesRectified(
bool enabled)
1227 #ifdef RTABMAP_REALSENSE2
1228 rectifyImages_ = enabled;
1232 void CameraRealSense2::setOdomProvided(
bool enabled,
bool imageStreamsDisabled,
bool onlyLeftStream)
1234 #ifdef RTABMAP_REALSENSE2
1235 if(dualMode_ && !enabled)
1237 UERROR(
"Odometry is disabled but dual mode was enabled, disabling dual mode.");
1240 odometryProvided_ = enabled;
1241 odometryImagesDisabled_ = enabled && imageStreamsDisabled;
1242 odometryOnlyLeftStream_ = enabled && !imageStreamsDisabled && onlyLeftStream;
1249 #ifdef RTABMAP_REALSENSE2
1252 auto frameset = syncer_.wait_for_frames(5000);
1254 int desiredFramesetSize = 2;
1255 while ((
int)frameset.size() != desiredFramesetSize &&
timer.
elapsed() < 2.0)
1258 frameset = syncer_.wait_for_frames(100);
1260 if ((
int)frameset.size() == desiredFramesetSize)
1263 bool is_rgb_arrived =
false;
1264 bool is_depth_arrived =
false;
1265 bool is_left_fisheye_arrived =
false;
1266 bool is_right_fisheye_arrived =
false;
1267 rs2::frame rgb_frame;
1268 rs2::frame depth_frame;
1269 double stamp = frameset.get_timestamp();
1270 for (
auto it = frameset.begin(); it != frameset.end(); ++it)
1273 if(stamp >
f.get_timestamp())
1275 stamp =
f.get_timestamp();
1277 auto stream_type =
f.get_profile().stream_type();
1278 if (stream_type == RS2_STREAM_COLOR || stream_type == RS2_STREAM_INFRARED)
1280 if(ir_ && !irDepth_)
1283 if(!is_depth_arrived)
1286 is_depth_arrived =
true;
1291 is_rgb_arrived =
true;
1297 is_rgb_arrived =
true;
1300 else if (stream_type == RS2_STREAM_DEPTH)
1303 is_depth_arrived =
true;
1305 else if (stream_type == RS2_STREAM_FISHEYE)
1307 if(!is_right_fisheye_arrived)
1310 is_right_fisheye_arrived =
true;
1315 is_left_fisheye_arrived =
true;
1321 UDEBUG(
"Frameset arrived. system=%fs frame=%fs", now, stamp);
1322 if(stamp - now > 1000000000.0)
1324 if(!clockSyncWarningShown_)
1326 UWARN(
"Clocks are not sync with host computer! Detected stamps in far "
1327 "future %f, thus using host time instead (%f)! This message "
1328 "will only appear once. "
1329 "See https://github.com/IntelRealSense/librealsense/issues/4505 "
1330 "for more info", stamp, now);
1331 clockSyncWarningShown_ =
true;
1336 if(is_rgb_arrived && is_depth_arrived)
1339 if(ir_ && !irDepth_)
1341 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()).clone();
1345 rs2::align align(rgb_frame.get_profile().stream_type());
1346 rs2::frameset processed = frameset.apply_filter(align);
1347 rs2::depth_frame aligned_depth_frame = processed.get_depth_frame();
1348 if(frameset.get_depth_frame().get_width() < aligned_depth_frame.get_width() &&
1349 frameset.get_depth_frame().get_height() < aligned_depth_frame.get_height())
1351 int decimationWidth =
int(
float(aligned_depth_frame.get_width())/
float(frameset.get_depth_frame().get_width())+0.5f);
1352 int decimationHeight =
int(
float(aligned_depth_frame.get_height())/
float(frameset.get_depth_frame().get_height())+0.5f);
1353 if(decimationWidth>1 || decimationHeight>1)
1355 depth =
util2d::decimate(cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()), decimationWidth>decimationHeight?decimationWidth:decimationHeight);
1359 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()).clone();
1364 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()).clone();
1366 if(depth_scale_meters_ != 0.001
f)
1368 if(depth.type() == CV_16UC1)
1370 float scaleMM = depth_scale_meters_ / 0.001f;
1371 depth = scaleMM * depth;
1376 cv::Mat rgb = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data());
1378 if(rgb.channels() == 3)
1380 cv::cvtColor(rgb, bgr, CV_RGB2BGR);
1387 if(ir_ && !irDepth_)
1390 data =
SensorData(bgr, depth, stereoModel_, this->getNextSeqID(), stamp);
1394 data =
SensorData(bgr, depth, model_, this->getNextSeqID(), stamp);
1397 else if(is_left_fisheye_arrived)
1399 if(odometryOnlyLeftStream_)
1402 if(rectifyImages_ && model_.isValidForRectification())
1404 left = model_.rectifyImage(cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()));
1408 left = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()).clone();
1411 if(model_.imageHeight() == 0 || model_.imageWidth() == 0)
1413 model_.setImageSize(left.size());
1416 data =
SensorData(left, cv::Mat(), model_, this->getNextSeqID(), stamp);
1418 else if(is_right_fisheye_arrived)
1421 if(rectifyImages_ && stereoModel_.left().isValidForRectification() && stereoModel_.right().isValidForRectification())
1423 left = stereoModel_.left().rectifyImage(cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()));
1424 right = stereoModel_.right().rectifyImage(cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()));
1428 left = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()).clone();
1429 right = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()).clone();
1432 if(stereoModel_.left().imageHeight() == 0 || stereoModel_.left().imageWidth() == 0)
1434 stereoModel_.setImageSize(left.size());
1437 data =
SensorData(left, right, stereoModel_, this->getNextSeqID(), stamp);
1442 UERROR(
"Not received depth and rgb");
1446 unsigned int confidence = 0;
1447 double imuStamp = stamp*1000.0;
1449 getPoseAndIMU(imuStamp, pose, confidence, imu);
1451 if(
info && odometryProvided_ && !pose.
isNull())
1454 info->odomPose = this->getLocalTransform() * pose * this->getLocalTransform().
inverse();
1456 info->odomCovariance = cv::Mat::eye(6,6,CV_64FC1) * 0.0001;
1457 info->odomCovariance.rowRange(0,3) *=
pow(10, 3-(
int)confidence);
1458 info->odomCovariance.rowRange(3,6) *=
pow(10, 1-(
int)confidence);
1460 if(!imu.
empty() && !isInterIMUPublishing())
1464 else if(isInterIMUPublishing() && !gyroBuffer_.empty())
1466 if(lastImuStamp_ > 0.0)
1468 UASSERT(imuStamp > lastImuStamp_);
1470 std::map<double, cv::Vec3f>::iterator iterA = gyroBuffer_.upper_bound(lastImuStamp_);
1471 std::map<double, cv::Vec3f>::iterator iterB = gyroBuffer_.lower_bound(imuStamp);
1472 if(iterA != gyroBuffer_.end())
1476 if(iterB != gyroBuffer_.end())
1480 std::vector<double> stamps;
1481 for(;iterA != iterB;++iterA)
1483 stamps.push_back(iterA->first);
1488 for(
size_t i=0;
i<stamps.size(); ++
i)
1492 getPoseAndIMU(stamps[
i], tmp, confidence, imuTmp);
1495 this->postInterIMU(imuTmp, stamps[
i]/1000.0);
1505 UDEBUG(
"inter imu published=%d (rate=%fHz), %f -> %f", pub,
double(pub)/((stamps.back()-stamps.front())/1000.0), stamps.front()/1000.0, stamps.back()/1000.0);
1509 UWARN(
"No inter imu published!?");
1512 lastImuStamp_ = imuStamp;
1515 else if(frameset.size()==1 && frameset[0].get_profile().stream_type() == RS2_STREAM_FISHEYE)
1517 UERROR(
"Missing frames (received %d, needed=%d). For T265 camera, "
1518 "either use realsense sdk v2.42.0, or apply "
1519 "this patch (https://github.com/IntelRealSense/librealsense/issues/9030#issuecomment-962223017) "
1520 "to fix this problem.", (
int)frameset.size(), desiredFramesetSize);
1524 UERROR(
"Missing frames (received %d, needed=%d)", (
int)frameset.size(), desiredFramesetSize);
1527 catch(
const std::exception& ex)
1529 UERROR(
"An error has occurred during frame callback: %s", ex.what());
1532 UERROR(
"CameraRealSense2: RTAB-Map is not built with RealSense2 support!");