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 if(sensors[1].supports(rs2_option::RS2_OPTION_EMITTER_ENABLED))
637 sensors[1].set_option(rs2_option::RS2_OPTION_EMITTER_ENABLED, emitterEnabled_);
640 else if (
"Coded-Light Depth Sensor" == module_name)
643 else if (
"RGB Camera" == module_name)
650 else if (
"Wide FOV Camera" == module_name)
653 else if (
"Motion Module" == module_name)
661 else if (
"Tracking Module" == module_name)
672 sensors.back() = elem;
673 sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_POSE_JUMPING, 0);
674 sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_RELOCALIZATION, 0);
676 else if (
"L500 Depth Sensor" == module_name)
682 cameraWidth_ = cameraDepthWidth_;
683 cameraHeight_ = cameraDepthHeight_;
684 cameraFps_ = cameraDepthFps_;
693 UINFO(
"%s was found.", elem.get_info(RS2_CAMERA_INFO_NAME));
698 model_ = CameraModel();
699 std::vector<std::vector<rs2::stream_profile> > profilesPerSensor(sensors.size());
700 for (
unsigned int i=0;
i<sensors.size(); ++
i)
702 if(i==0 && ir_ && !stereo)
706 UINFO(
"Sensor %d \"%s\"", (
int)i, sensors[i].get_info(RS2_CAMERA_INFO_NAME));
707 auto profiles = sensors[
i].get_stream_profiles();
709 UINFO(
"profiles=%d", (
int)profiles.size());
714 auto video_profile =
profile.as<rs2::video_stream_profile>();
715 UINFO(
"%s %d %d %d %d %s type=%d", rs2_format_to_string(
716 video_profile.format()),
717 video_profile.width(),
718 video_profile.height(),
720 video_profile.stream_index(),
721 video_profile.stream_name().c_str(),
722 video_profile.stream_type());
728 auto video_profile =
profile.as<rs2::video_stream_profile>();
731 if( (video_profile.width() == cameraWidth_ &&
732 video_profile.height() == cameraHeight_ &&
733 video_profile.fps() == cameraFps_) ||
734 (strcmp(sensors[i].get_info(RS2_CAMERA_INFO_NAME),
"L500 Depth Sensor")==0 &&
735 video_profile.width() == cameraDepthWidth_ &&
736 video_profile.height() == cameraDepthHeight_ &&
737 video_profile.fps() == cameraDepthFps_))
739 auto intrinsic = video_profile.get_intrinsics();
742 if((!ir_ && video_profile.format() == RS2_FORMAT_RGB8 && video_profile.stream_type() == RS2_STREAM_COLOR) ||
743 (ir_ && video_profile.format() == RS2_FORMAT_Y8 && (video_profile.stream_index() == 1 || isL500)))
745 if(!profilesPerSensor[i].
empty())
748 profilesPerSensor[
i].push_back(profilesPerSensor[i].back());
749 profilesPerSensor[
i].front() =
profile;
753 profilesPerSensor[
i].push_back(
profile);
755 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));
756 model_ = CameraModel(camera_name, intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
this->getLocalTransform(), 0, cv::Size(intrinsic.width, intrinsic.height));
757 UINFO(
"Model: %dx%d fx=%f fy=%f cx=%f cy=%f dist model=%d coeff=%f %f %f %f %f",
758 intrinsic.width, intrinsic.height,
759 intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
761 intrinsic.coeffs[0], intrinsic.coeffs[1], intrinsic.coeffs[2], intrinsic.coeffs[3], intrinsic.coeffs[4]);
763 if(video_profile.format() == RS2_FORMAT_RGB8 || profilesPerSensor[i].size()==2)
769 else if(((!ir_ || irDepth_) && video_profile.format() == RS2_FORMAT_Z16) ||
770 (ir_ && !irDepth_ && video_profile.format() == RS2_FORMAT_Y8 && video_profile.stream_index() == 2))
772 profilesPerSensor[
i].push_back(
profile);
773 depthBuffer_ = cv::Mat(cv::Size(cameraWidth_, cameraHeight_), video_profile.format() == RS2_FORMAT_Y8?CV_8UC1:CV_16UC1, cv::Scalar(0));
775 if(!ir_ || irDepth_ || profilesPerSensor[i].
size()==2)
781 else if(video_profile.format() == RS2_FORMAT_MOTION_XYZ32F || video_profile.format() == RS2_FORMAT_6DOF)
792 bool modified =
false;
793 for (
size_t j= 0;
j < profilesPerSensor[
i].size(); ++
j)
795 if (profilesPerSensor[i][j].stream_type() ==
profile.stream_type())
797 if (
profile.stream_type() == RS2_STREAM_ACCEL)
799 if(
profile.fps() > profilesPerSensor[i][j].fps())
803 else if (
profile.stream_type() == RS2_STREAM_GYRO)
805 if(
profile.fps() < profilesPerSensor[i][j].fps())
812 profilesPerSensor[
i].push_back(
profile);
816 else if(stereo || dualMode_)
820 video_profile.format() == RS2_FORMAT_Y8 &&
821 video_profile.width() == 848 &&
822 video_profile.height() == 800 &&
823 video_profile.fps() == 30)
826 profilesPerSensor[
i].push_back(
profile);
830 rgbBuffer_ = cv::Mat(cv::Size(848, 800), CV_8UC1, cv::Scalar(0));
831 if(odometryOnlyLeftStream_)
833 auto intrinsic = video_profile.get_intrinsics();
834 UINFO(
"Model: %dx%d fx=%f fy=%f cx=%f cy=%f dist model=%d coeff=%f %f %f %f",
835 intrinsic.width, intrinsic.height,
836 intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy,
838 intrinsic.coeffs[0], intrinsic.coeffs[1], intrinsic.coeffs[2], intrinsic.coeffs[3]);
839 cv::Mat
K = cv::Mat::eye(3,3,CV_64FC1);
840 K.at<
double>(0,0) = intrinsic.fx;
841 K.at<
double>(1,1) = intrinsic.fy;
842 K.at<
double>(0,2) = intrinsic.ppx;
843 K.at<
double>(1,2) = intrinsic.ppy;
844 UASSERT(intrinsic.model == RS2_DISTORTION_KANNALA_BRANDT4);
845 cv::Mat
D = cv::Mat::zeros(1,6,CV_64FC1);
846 D.at<
double>(0,0) = intrinsic.coeffs[0];
847 D.at<
double>(0,1) = intrinsic.coeffs[1];
848 D.at<
double>(0,4) = intrinsic.coeffs[2];
849 D.at<
double>(0,5) = intrinsic.coeffs[3];
850 cv::Mat
P = cv::Mat::eye(3, 4, CV_64FC1);
851 P.at<
double>(0,0) = intrinsic.fx;
852 P.at<
double>(1,1) = intrinsic.fy;
853 P.at<
double>(0,2) = intrinsic.ppx;
854 P.at<
double>(1,2) = intrinsic.ppy;
855 cv::Mat
R = cv::Mat::eye(3, 3, CV_64FC1);
856 model_ = CameraModel(camera_name, cv::Size(intrinsic.width, intrinsic.height), K, D, R,
P,
this->getLocalTransform());
858 model_.initRectificationMap();
861 else if(!odometryOnlyLeftStream_)
864 depthBuffer_ = cv::Mat(cv::Size(848, 800), CV_8UC1, cv::Scalar(0));
868 else if(video_profile.format() == RS2_FORMAT_MOTION_XYZ32F || video_profile.format() == RS2_FORMAT_6DOF)
873 profilesPerSensor[
i].push_back(
profile);
881 UERROR(
"Given stream configuration is not supported by the device! "
882 "Stream Index: %d, Width: %d, Height: %d, FPS: %d", i, cameraWidth_, cameraHeight_, cameraFps_);
883 UERROR(
"Available configurations:");
886 auto video_profile =
profile.as<rs2::video_stream_profile>();
887 UERROR(
"%s %d %d %d %d %s type=%d", rs2_format_to_string(
888 video_profile.format()),
889 video_profile.width(),
890 video_profile.height(),
892 video_profile.stream_index(),
893 video_profile.stream_name().c_str(),
894 video_profile.stream_type());
902 if(!model_.isValidForProjection())
904 UERROR(
"Calibration info not valid!");
905 std::cout<< model_ << std::endl;
911 UINFO(
"Set base to pose");
913 UINFO(
"dualExtrinsics_ = %s", dualExtrinsics_.prettyPrint().c_str());
914 Transform baseToCam = this->getLocalTransform()*dualExtrinsics_;
915 UASSERT(profilesPerSensor.size()>=2);
916 UASSERT(profilesPerSensor.back().size() == 3);
917 rs2_extrinsics poseToIMU = profilesPerSensor.back()[0].get_extrinsics_to(profilesPerSensor.back()[2]);
919 Transform poseToIMUT(
920 poseToIMU.rotation[0], poseToIMU.rotation[1], poseToIMU.rotation[2], poseToIMU.translation[0],
921 poseToIMU.rotation[3], poseToIMU.rotation[4], poseToIMU.rotation[5], poseToIMU.translation[1],
922 poseToIMU.rotation[6], poseToIMU.rotation[7], poseToIMU.rotation[8], poseToIMU.translation[2]);
923 poseToIMUT = realsense2PoseRotation_ * poseToIMUT;
924 UINFO(
"poseToIMU = %s", poseToIMUT.prettyPrint().c_str());
926 UINFO(
"BaseToCam = %s", baseToCam.prettyPrint().c_str());
927 model_.setLocalTransform(baseToCam);
928 imuLocalTransform_ = this->getLocalTransform() * poseToIMUT;
931 if(ir_ && !irDepth_ && profilesPerSensor.size() >= 2 && profilesPerSensor[1].size() >= 2)
933 rs2_extrinsics leftToRight = profilesPerSensor[1][1].get_extrinsics_to(profilesPerSensor[1][0]);
934 Transform leftToRightT(
935 leftToRight.rotation[0], leftToRight.rotation[1], leftToRight.rotation[2], leftToRight.translation[0],
936 leftToRight.rotation[3], leftToRight.rotation[4], leftToRight.rotation[5], leftToRight.translation[1],
937 leftToRight.rotation[6], leftToRight.rotation[7], leftToRight.rotation[8], leftToRight.translation[2]);
939 UINFO(
"left to right transform = %s", leftToRightT.prettyPrint().c_str());
942 stereoModel_ = StereoCameraModel(model_.fx(), model_.fy(), model_.cx(), model_.cy(), leftToRightT.x(), model_.localTransform(), model_.imageSize());
943 UINFO(
"Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
944 stereoModel_.left().fx(),
945 stereoModel_.left().cx(),
946 stereoModel_.left().cy(),
947 stereoModel_.baseline());
950 if(!dualMode_ && profilesPerSensor.size() == 3)
952 if(!profilesPerSensor[2].
empty() && !profilesPerSensor[0].
empty())
954 rs2_extrinsics leftToIMU = profilesPerSensor[2][0].get_extrinsics_to(profilesPerSensor[0][0]);
955 Transform leftToIMUT(
956 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
957 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
958 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
959 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
960 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
962 else if(!profilesPerSensor[2].
empty() && !profilesPerSensor[1].
empty())
964 rs2_extrinsics leftToIMU = profilesPerSensor[2][0].get_extrinsics_to(profilesPerSensor[1][0]);
965 Transform leftToIMUT(
966 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
967 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
968 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
970 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
971 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
979 std::string serial = sn;
980 if(!cameraName.empty())
984 if(!odometryImagesDisabled_ &&
985 !odometryOnlyLeftStream_ &&
986 !calibrationFolder.empty() && !serial.empty())
988 if(!stereoModel_.load(calibrationFolder, serial,
false))
990 UWARN(
"Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
991 serial.c_str(), calibrationFolder.c_str());
995 UINFO(
"Stereo parameters: fx=%f cx=%f cy=%f baseline=%f",
996 stereoModel_.left().fx(),
997 stereoModel_.left().cx(),
998 stereoModel_.left().cy(),
999 stereoModel_.baseline());
1010 if(odometryProvided_)
1012 rs2_extrinsics poseToLeft = profilesPerSensor[0][0].get_extrinsics_to(profilesPerSensor[0][4]);
1013 rs2_extrinsics poseToIMU = profilesPerSensor[0][2].get_extrinsics_to(profilesPerSensor[0][4]);
1014 Transform poseToLeftT(
1015 poseToLeft.rotation[0], poseToLeft.rotation[1], poseToLeft.rotation[2], poseToLeft.translation[0],
1016 poseToLeft.rotation[3], poseToLeft.rotation[4], poseToLeft.rotation[5], poseToLeft.translation[1],
1017 poseToLeft.rotation[6], poseToLeft.rotation[7], poseToLeft.rotation[8], poseToLeft.translation[2]);
1018 poseToLeftT = realsense2PoseRotation_ * poseToLeftT;
1019 UINFO(
"poseToLeft = %s", poseToLeftT.prettyPrint().c_str());
1021 Transform poseToIMUT(
1022 poseToIMU.rotation[0], poseToIMU.rotation[1], poseToIMU.rotation[2], poseToIMU.translation[0],
1023 poseToIMU.rotation[3], poseToIMU.rotation[4], poseToIMU.rotation[5], poseToIMU.translation[1],
1024 poseToIMU.rotation[6], poseToIMU.rotation[7], poseToIMU.rotation[8], poseToIMU.translation[2]);
1025 poseToIMUT = realsense2PoseRotation_ * poseToIMUT;
1026 UINFO(
"poseToIMU = %s", poseToIMUT.prettyPrint().c_str());
1028 Transform opticalTransform(0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0);
1029 this->setLocalTransform(this->getLocalTransform() * opticalTransform.inverse());
1030 if(odometryOnlyLeftStream_)
1031 model_.setLocalTransform(this->getLocalTransform()*poseToLeftT);
1033 stereoModel_.setLocalTransform(this->getLocalTransform()*poseToLeftT);
1034 imuLocalTransform_ = this->getLocalTransform()* poseToIMUT;
1036 if(odometryImagesDisabled_)
1039 std::vector<rs2::stream_profile> profiles;
1040 profiles.push_back(profilesPerSensor[0][4]);
1041 profilesPerSensor[0] = profiles;
1047 rs2_extrinsics leftToIMU = profilesPerSensor[0][2].get_extrinsics_to(profilesPerSensor[0][0]);
1048 Transform leftToIMUT(
1049 leftToIMU.rotation[0], leftToIMU.rotation[1], leftToIMU.rotation[2], leftToIMU.translation[0],
1050 leftToIMU.rotation[3], leftToIMU.rotation[4], leftToIMU.rotation[5], leftToIMU.translation[1],
1051 leftToIMU.rotation[6], leftToIMU.rotation[7], leftToIMU.rotation[8], leftToIMU.translation[2]);
1052 UINFO(
"leftToIMU = %s", leftToIMUT.prettyPrint().c_str());
1053 imuLocalTransform_ = this->getLocalTransform() * leftToIMUT;
1054 UINFO(
"imu local transform = %s", imuLocalTransform_.prettyPrint().c_str());
1055 if(odometryOnlyLeftStream_)
1056 model_.setLocalTransform(this->getLocalTransform());
1058 stereoModel_.setLocalTransform(this->getLocalTransform());
1060 if(!odometryImagesDisabled_ && rectifyImages_ && !model_.isValidForRectification() && !stereoModel_.isValidForRectification())
1062 UERROR(
"Parameter \"rectifyImages\" is set, but no stereo model is loaded or valid.");
1067 std::function<void(rs2::frame)> multiple_message_callback_function = [
this](rs2::frame frame){multiple_message_callback(frame);};
1069 for (
unsigned int i=0;
i<sensors.size(); ++
i)
1071 if(profilesPerSensor[i].
size())
1073 UINFO(
"Starting sensor %d with %d profiles", (
int)i, (
int)profilesPerSensor[i].
size());
1074 for (
size_t j = 0;
j < profilesPerSensor[
i].size(); ++
j)
1076 auto video_profile = profilesPerSensor[
i][
j].as<rs2::video_stream_profile>();
1077 UINFO(
"Opening: %s %d %d %d %d %s type=%d", rs2_format_to_string(
1078 video_profile.format()),
1079 video_profile.width(),
1080 video_profile.height(),
1081 video_profile.fps(),
1082 video_profile.stream_index(),
1083 video_profile.stream_name().c_str(),
1084 video_profile.stream_type());
1086 if(globalTimeSync_ && sensors[i].supports(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED))
1088 float value = sensors[
i].get_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED);
1089 UINFO(
"Set RS2_OPTION_GLOBAL_TIME_ENABLED=1 (was %f) for sensor %d", value, (
int)i);
1090 sensors[
i].set_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED, 1);
1092 sensors[
i].open(profilesPerSensor[i]);
1093 if(sensors[i].is<rs2::depth_sensor>())
1095 auto depth_sensor = sensors[
i].as<rs2::depth_sensor>();
1096 depth_scale_meters_ = depth_sensor.get_depth_scale();
1097 UINFO(
"Depth scale %f for sensor %d", depth_scale_meters_, (
int)i);
1099 sensors[
i].start(multiple_message_callback_function);
1104 UINFO(
"Enabling streams...done!");
1109 UERROR(
"CameraRealSense: RTAB-Map is not built with RealSense2 support!");
1114 bool CameraRealSense2::isCalibrated()
const
1116 #ifdef RTABMAP_REALSENSE2
1117 return model_.isValidForProjection() || stereoModel_.isValidForRectification();
1123 std::string CameraRealSense2::getSerial()
const
1125 #ifdef RTABMAP_REALSENSE2
1128 return dev_[0].get_info(RS2_CAMERA_INFO_SERIAL_NUMBER);
1134 bool CameraRealSense2::odomProvided()
const
1136 #ifdef RTABMAP_REALSENSE2
1137 return odometryProvided_;
1143 bool CameraRealSense2::getPose(
double stamp,
Transform & pose, cv::Mat & covariance,
double maxWaitTime)
1145 #ifdef RTABMAP_REALSENSE2
1147 unsigned int confidence = 0;
1148 double rsStamp = stamp*1000.0;
1150 getPoseAndIMU(rsStamp,
p, confidence, imu, maxWaitTime*1000);
1155 pose = this->getLocalTransform() *
p * this->getLocalTransform().inverse();
1157 covariance = cv::Mat::eye(6,6,CV_64FC1) * 0.0001;
1158 covariance.rowRange(0,3) *=
pow(10, 3-(
int)confidence);
1159 covariance.rowRange(3,6) *=
pow(10, 1-(
int)confidence);
1166 void CameraRealSense2::setEmitterEnabled(
bool enabled)
1168 #ifdef RTABMAP_REALSENSE2
1169 emitterEnabled_ = enabled;
1173 void CameraRealSense2::setIRFormat(
bool enabled,
bool useDepthInsteadOfRightImage)
1175 #ifdef RTABMAP_REALSENSE2
1177 irDepth_ = useDepthInsteadOfRightImage;
1181 void CameraRealSense2::setResolution(
int width,
int height,
int fps)
1183 #ifdef RTABMAP_REALSENSE2
1184 cameraWidth_ = width;
1185 cameraHeight_ = height;
1190 void CameraRealSense2::setDepthResolution(
int width,
int height,
int fps)
1192 #ifdef RTABMAP_REALSENSE2
1193 cameraDepthWidth_ = width;
1194 cameraDepthHeight_ = height;
1195 cameraDepthFps_ = fps;
1199 void CameraRealSense2::setGlobalTimeSync(
bool enabled)
1201 #ifdef RTABMAP_REALSENSE2
1202 globalTimeSync_ = enabled;
1206 void CameraRealSense2::setDualMode(
bool enabled,
const Transform & extrinsics)
1208 #ifdef RTABMAP_REALSENSE2
1210 dualMode_ = enabled;
1211 dualExtrinsics_ = extrinsics*CameraModel::opticalRotation();
1214 odometryProvided_ =
true;
1215 odometryImagesDisabled_ =
false;
1216 odometryOnlyLeftStream_ =
false;
1221 void CameraRealSense2::setJsonConfig(
const std::string & json)
1223 #ifdef RTABMAP_REALSENSE2
1228 void CameraRealSense2::setImagesRectified(
bool enabled)
1230 #ifdef RTABMAP_REALSENSE2
1231 rectifyImages_ = enabled;
1235 void CameraRealSense2::setOdomProvided(
bool enabled,
bool imageStreamsDisabled,
bool onlyLeftStream)
1237 #ifdef RTABMAP_REALSENSE2
1238 if(dualMode_ && !enabled)
1240 UERROR(
"Odometry is disabled but dual mode was enabled, disabling dual mode.");
1243 odometryProvided_ = enabled;
1244 odometryImagesDisabled_ = enabled && imageStreamsDisabled;
1245 odometryOnlyLeftStream_ = enabled && !imageStreamsDisabled && onlyLeftStream;
1252 #ifdef RTABMAP_REALSENSE2
1255 auto frameset = syncer_.wait_for_frames(5000);
1257 int desiredFramesetSize = 2;
1258 while ((
int)frameset.size() != desiredFramesetSize &&
timer.
elapsed() < 2.0)
1261 frameset = syncer_.wait_for_frames(100);
1263 if ((
int)frameset.size() == desiredFramesetSize)
1266 bool is_rgb_arrived =
false;
1267 bool is_depth_arrived =
false;
1268 bool is_left_fisheye_arrived =
false;
1269 bool is_right_fisheye_arrived =
false;
1270 rs2::frame rgb_frame;
1271 rs2::frame depth_frame;
1272 double stamp = frameset.get_timestamp();
1273 for (
auto it = frameset.begin(); it != frameset.end(); ++it)
1276 if(stamp >
f.get_timestamp())
1278 stamp =
f.get_timestamp();
1280 auto stream_type =
f.get_profile().stream_type();
1281 if (stream_type == RS2_STREAM_COLOR || stream_type == RS2_STREAM_INFRARED)
1283 if(ir_ && !irDepth_)
1286 if(!is_depth_arrived)
1289 is_depth_arrived =
true;
1294 is_rgb_arrived =
true;
1300 is_rgb_arrived =
true;
1303 else if (stream_type == RS2_STREAM_DEPTH)
1306 is_depth_arrived =
true;
1308 else if (stream_type == RS2_STREAM_FISHEYE)
1310 if(!is_right_fisheye_arrived)
1313 is_right_fisheye_arrived =
true;
1318 is_left_fisheye_arrived =
true;
1324 UDEBUG(
"Frameset arrived. system=%fs frame=%fs", now, stamp);
1325 if(stamp - now > 1000000000.0)
1327 if(!clockSyncWarningShown_)
1329 UWARN(
"Clocks are not sync with host computer! Detected stamps in far "
1330 "future %f, thus using host time instead (%f)! This message "
1331 "will only appear once. "
1332 "See https://github.com/IntelRealSense/librealsense/issues/4505 "
1333 "for more info", stamp, now);
1334 clockSyncWarningShown_ =
true;
1339 if(is_rgb_arrived && is_depth_arrived)
1342 if(ir_ && !irDepth_)
1344 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()).clone();
1348 rs2::align align(rgb_frame.get_profile().stream_type());
1349 rs2::frameset processed = frameset.apply_filter(align);
1350 rs2::depth_frame aligned_depth_frame = processed.get_depth_frame();
1351 if(frameset.get_depth_frame().get_width() < aligned_depth_frame.get_width() &&
1352 frameset.get_depth_frame().get_height() < aligned_depth_frame.get_height())
1354 int decimationWidth =
int(
float(aligned_depth_frame.get_width())/
float(frameset.get_depth_frame().get_width())+0.5f);
1355 int decimationHeight =
int(
float(aligned_depth_frame.get_height())/
float(frameset.get_depth_frame().get_height())+0.5f);
1356 if(decimationWidth>1 || decimationHeight>1)
1358 depth =
util2d::decimate(cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()), decimationWidth>decimationHeight?decimationWidth:decimationHeight);
1362 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()).clone();
1367 depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)aligned_depth_frame.get_data()).clone();
1369 if(depth_scale_meters_ != 0.001
f)
1371 if(depth.type() == CV_16UC1)
1373 float scaleMM = depth_scale_meters_ / 0.001f;
1374 depth = scaleMM * depth;
1379 cv::Mat rgb = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data());
1381 if(rgb.channels() == 3)
1383 cv::cvtColor(rgb, bgr, CV_RGB2BGR);
1390 if(ir_ && !irDepth_)
1393 data =
SensorData(bgr, depth, stereoModel_, this->getNextSeqID(), stamp);
1397 data =
SensorData(bgr, depth, model_, this->getNextSeqID(), stamp);
1400 else if(is_left_fisheye_arrived)
1402 if(odometryOnlyLeftStream_)
1405 if(rectifyImages_ && model_.isValidForRectification())
1407 left = model_.rectifyImage(cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()));
1411 left = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()).clone();
1414 if(model_.imageHeight() == 0 || model_.imageWidth() == 0)
1416 model_.setImageSize(left.size());
1419 data =
SensorData(left, cv::Mat(), model_, this->getNextSeqID(), stamp);
1421 else if(is_right_fisheye_arrived)
1424 if(rectifyImages_ && stereoModel_.left().isValidForRectification() && stereoModel_.right().isValidForRectification())
1426 left = stereoModel_.left().rectifyImage(cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()));
1427 right = stereoModel_.right().rectifyImage(cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()));
1431 left = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (
void*)rgb_frame.get_data()).clone();
1432 right = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (
void*)depth_frame.get_data()).clone();
1435 if(stereoModel_.left().imageHeight() == 0 || stereoModel_.left().imageWidth() == 0)
1437 stereoModel_.setImageSize(left.size());
1440 data =
SensorData(left, right, stereoModel_, this->getNextSeqID(), stamp);
1445 UERROR(
"Not received depth and rgb");
1449 unsigned int confidence = 0;
1450 double imuStamp = stamp*1000.0;
1452 getPoseAndIMU(imuStamp, pose, confidence, imu);
1454 if(
info && odometryProvided_ && !pose.
isNull())
1457 info->odomPose = this->getLocalTransform() * pose * this->getLocalTransform().
inverse();
1459 info->odomCovariance = cv::Mat::eye(6,6,CV_64FC1) * 0.0001;
1460 info->odomCovariance.rowRange(0,3) *=
pow(10, 3-(
int)confidence);
1461 info->odomCovariance.rowRange(3,6) *=
pow(10, 1-(
int)confidence);
1463 if(!imu.
empty() && !isInterIMUPublishing())
1467 else if(isInterIMUPublishing() && !gyroBuffer_.empty())
1469 if(lastImuStamp_ > 0.0)
1471 UASSERT(imuStamp > lastImuStamp_);
1473 std::map<double, cv::Vec3f>::iterator iterA = gyroBuffer_.upper_bound(lastImuStamp_);
1474 std::map<double, cv::Vec3f>::iterator iterB = gyroBuffer_.lower_bound(imuStamp);
1475 if(iterA != gyroBuffer_.end())
1479 if(iterB != gyroBuffer_.end())
1483 std::vector<double> stamps;
1484 for(;iterA != iterB;++iterA)
1486 stamps.push_back(iterA->first);
1491 for(
size_t i=0;
i<stamps.size(); ++
i)
1495 getPoseAndIMU(stamps[
i], tmp, confidence, imuTmp);
1498 this->postInterIMU(imuTmp, stamps[
i]/1000.0);
1508 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);
1512 UWARN(
"No inter imu published!?");
1515 lastImuStamp_ = imuStamp;
1518 else if(frameset.size()==1 && frameset[0].get_profile().stream_type() == RS2_STREAM_FISHEYE)
1520 UERROR(
"Missing frames (received %d, needed=%d). For T265 camera, "
1521 "either use realsense sdk v2.42.0, or apply "
1522 "this patch (https://github.com/IntelRealSense/librealsense/issues/9030#issuecomment-962223017) "
1523 "to fix this problem.", (
int)frameset.size(), desiredFramesetSize);
1527 UERROR(
"Missing frames (received %d, needed=%d)", (
int)frameset.size(), desiredFramesetSize);
1530 catch(
const std::exception& ex)
1532 UERROR(
"An error has occurred during frame callback: %s", ex.what());
1535 UERROR(
"CameraRealSense2: RTAB-Map is not built with RealSense2 support!");