diff --git a/README.md b/README.md index d3acce0d..3baba88c 100644 --- a/README.md +++ b/README.md @@ -231,6 +231,12 @@ Parameters: * `COPY` * `LINEAR_INTERPOLATE_GYRO` * `LINEAR_INTERPOLATE_ACCEL` +* `i_rotation_vector_type` - type of rotation vector, for more information, refer to [this link](https://docs.luxonis.com/projects/api/en/latest/components/nodes/imu/). Available options: + * `ROTATION_VECTOR` + * `GAME_ROTATION_VECTOR` + * `GEOMAGNETIC_ROTATION_VECTOR` + * `ARVR_STABILIZED_ROTATION_VECTOR` + * `ARVR_STABILIZED_GAME_ROTATION_VECTOR` #### Stopping/starting camera for power saving/reconfiguration ![](docs/start_stop.gif) @@ -451,6 +457,7 @@ For easier development inside isolated workspace, one can use Visual Studio Code i_max_batch_reports: 10 i_message_type: IMU i_rot_cov: -1.0 + i_rotation_vector_type: ROTATION_VECTOR i_sync_method: LINEAR_INTERPOLATE_ACCEL i_update_ros_base_time_on_ros_msg: false left: diff --git a/depthai_bridge/include/depthai_bridge/ImuConverter.hpp b/depthai_bridge/include/depthai_bridge/ImuConverter.hpp index 6cf7a36d..9dc5523f 100644 --- a/depthai_bridge/include/depthai_bridge/ImuConverter.hpp +++ b/depthai_bridge/include/depthai_bridge/ImuConverter.hpp @@ -33,6 +33,7 @@ class ImuConverter { double rotation_cov = 0.0, double magnetic_field_cov = 0.0, bool enable_rotation = false, + bool enable_magn = false, bool getBaseDeviceTimestamp = false); ~ImuConverter(); @@ -99,9 +100,9 @@ class ImuConverter { rotationHist.resize(accelHist.size()); } - if(_enable_rotation && magnHist.size() == 0) { + if(_enable_magn && magnHist.size() == 0) { magnHist.push_back(imuPackets[i].magneticField); - } else if(_enable_rotation && magnHist.back().sequence != imuPackets[i].magneticField.sequence) { + } else if(_enable_magn && magnHist.back().sequence != imuPackets[i].magneticField.sequence) { magnHist.push_back(imuPackets[i].magneticField); } else { magnHist.resize(accelHist.size()); @@ -112,7 +113,11 @@ class ImuConverter { continue; } else { if(_enable_rotation) { - interpolate(accelHist, gyroHist, rotationHist, magnHist, imuMsgs); + if(_enable_magn) { + interpolate(accelHist, gyroHist, rotationHist, magnHist, imuMsgs); + } else { + interpolate(accelHist, gyroHist, rotationHist, imuMsgs); + } } else { interpolate(accelHist, gyroHist, imuMsgs); } @@ -123,7 +128,11 @@ class ImuConverter { continue; } else { if(_enable_rotation) { - interpolate(gyroHist, accelHist, rotationHist, magnHist, imuMsgs); + if(_enable_magn) { + interpolate(gyroHist, accelHist, rotationHist, magnHist, imuMsgs); + } else { + interpolate(gyroHist, accelHist, rotationHist, imuMsgs); + } } else { interpolate(gyroHist, accelHist, imuMsgs); } @@ -135,6 +144,7 @@ class ImuConverter { uint32_t _sequenceNum; double _linear_accel_cov, _angular_velocity_cov, _rotation_cov, _magnetic_field_cov; bool _enable_rotation; + bool _enable_magn; const std::string _frameName = ""; ImuSyncMethod _syncMode; std::chrono::time_point _steadyBaseTime; @@ -145,22 +155,33 @@ class ImuConverter { // Whether to update the ROS base time on each message conversion bool _updateRosBaseTimeOnToRosMsg{false}; - void fillImuMsg(dai::IMUReportAccelerometer report, ImuMsgs::Imu& msg); - void fillImuMsg(dai::IMUReportGyroscope report, ImuMsgs::Imu& msg); - void fillImuMsg(dai::IMUReportRotationVectorWAcc report, ImuMsgs::Imu& msg); - void fillImuMsg(dai::IMUReportMagneticField report, ImuMsgs::Imu& msg); + void fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportAccelerometer report); + void fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportGyroscope report); + void fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportRotationVectorWAcc report); + void fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportMagneticField report); - void fillImuMsg(dai::IMUReportAccelerometer report, depthai_ros_msgs::msg::ImuWithMagneticField& msg); - void fillImuMsg(dai::IMUReportGyroscope report, depthai_ros_msgs::msg::ImuWithMagneticField& msg); - void fillImuMsg(dai::IMUReportRotationVectorWAcc report, depthai_ros_msgs::msg::ImuWithMagneticField& msg); - void fillImuMsg(dai::IMUReportMagneticField report, depthai_ros_msgs::msg::ImuWithMagneticField& msg); + void fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportAccelerometer report); + void fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportGyroscope report); + void fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportRotationVectorWAcc report); + void fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportMagneticField report); template - void CreateUnitMessage(I first, S second, T third, F fourth, M& msg, std::chrono::_V2::steady_clock::time_point timestamp) { - fillImuMsg(first, msg); - fillImuMsg(second, msg); - fillImuMsg(third, msg); - fillImuMsg(fourth, msg); + void CreateUnitMessage(M& msg, std::chrono::_V2::steady_clock::time_point timestamp, I first, S second, T third, F fourth) { + fillImuMsg(msg, first); + fillImuMsg(msg, second); + fillImuMsg(msg, third); + fillImuMsg(msg, fourth); + + msg.header.frame_id = _frameName; + + msg.header.stamp = getFrameTime(_rosBaseTime, _steadyBaseTime, timestamp); + } + + template + void CreateUnitMessage(M& msg, std::chrono::_V2::steady_clock::time_point timestamp, I first, S second, T third) { + fillImuMsg(msg, first); + fillImuMsg(msg, second); + fillImuMsg(msg, third); msg.header.frame_id = _frameName; @@ -168,9 +189,9 @@ class ImuConverter { } template - void CreateUnitMessage(I first, S second, M& msg, std::chrono::_V2::steady_clock::time_point timestamp) { - fillImuMsg(first, msg); - fillImuMsg(second, msg); + void CreateUnitMessage(M& msg, std::chrono::_V2::steady_clock::time_point timestamp, I first, S second) { + fillImuMsg(msg, first); + fillImuMsg(msg, second); msg.header.frame_id = _frameName; @@ -205,9 +226,63 @@ class ImuConverter { tstamp = currSecond.getTimestampDevice(); else tstamp = currSecond.getTimestamp(); - CreateUnitMessage(interp, currSecond, msg, tstamp); + CreateUnitMessage(msg, tstamp, interp, currSecond); + imuMsgs.push_back(msg); + second.pop_front(); + } else if(currSecond.timestamp.get() > interp1.timestamp.get()) { + interp0 = interp1; + if(interpolated.size()) { + interp1 = interpolated.front(); + interpolated.pop_front(); + duration_ms = interp1.timestamp.get() - interp0.timestamp.get(); + dt = duration_ms.count(); + } else { + break; + } + } else { + second.pop_front(); + } + } + interp0 = interp1; + } + } + interpolated.push_back(interp0); + } + + template + void interpolate(std::deque& interpolated, std::deque& second, std::deque& third, std::deque& imuMsgs) { + I interp0, interp1; + S currSecond; + T currThird; + interp0.sequence = -1; + while(interpolated.size()) { + if(interp0.sequence == -1) { + interp0 = interpolated.front(); + interpolated.pop_front(); + } else { + interp1 = interpolated.front(); + interpolated.pop_front(); + // remove std::milli to get in seconds + std::chrono::duration duration_ms = interp1.timestamp.get() - interp0.timestamp.get(); + double dt = duration_ms.count(); + while(second.size()) { + currSecond = second.front(); + currThird = third.front(); + if(currSecond.timestamp.get() > interp0.timestamp.get() && currSecond.timestamp.get() <= interp1.timestamp.get()) { + // remove std::milli to get in seconds + std::chrono::duration diff = currSecond.timestamp.get() - interp0.timestamp.get(); + const double alpha = diff.count() / dt; + I interp = lerpImu(interp0, interp1, alpha); + M msg; + std::chrono::_V2::steady_clock::time_point tstamp; + if(_getBaseDeviceTimestamp) + tstamp = currSecond.getTimestampDevice(); + else + tstamp = currSecond.getTimestamp(); + CreateUnitMessage(msg, tstamp, interp, currSecond, currThird); imuMsgs.push_back(msg); second.pop_front(); + third.pop_front(); } else if(currSecond.timestamp.get() > interp1.timestamp.get()) { interp0 = interp1; if(interpolated.size()) { @@ -220,6 +295,7 @@ class ImuConverter { } } else { second.pop_front(); + third.pop_front(); } } interp0 = interp1; @@ -260,7 +336,7 @@ class ImuConverter { tstamp = currSecond.getTimestampDevice(); else tstamp = currSecond.getTimestamp(); - CreateUnitMessage(interp, currSecond, currThird, currFourth, msg, tstamp); + CreateUnitMessage(msg, tstamp, interp, currSecond, currThird, currFourth); imuMsgs.push_back(msg); second.pop_front(); third.pop_front(); diff --git a/depthai_bridge/src/ImuConverter.cpp b/depthai_bridge/src/ImuConverter.cpp index e733d0f3..e6cf7933 100644 --- a/depthai_bridge/src/ImuConverter.cpp +++ b/depthai_bridge/src/ImuConverter.cpp @@ -14,6 +14,7 @@ ImuConverter::ImuConverter(const std::string& frameName, double rotation_cov, double magnetic_field_cov, bool enable_rotation, + bool enable_magn, bool getBaseDeviceTimestamp) : _frameName(frameName), _syncMode(syncMode), @@ -22,6 +23,7 @@ ImuConverter::ImuConverter(const std::string& frameName, _rotation_cov(rotation_cov), _magnetic_field_cov(magnetic_field_cov), _enable_rotation(enable_rotation), + _enable_magn(enable_magn), _sequenceNum(0), _steadyBaseTime(std::chrono::steady_clock::now()), _getBaseDeviceTimestamp(getBaseDeviceTimestamp) { @@ -34,21 +36,21 @@ void ImuConverter::updateRosBaseTime() { updateBaseTime(_steadyBaseTime, _rosBaseTime, _totalNsChange); } -void ImuConverter::fillImuMsg(dai::IMUReportAccelerometer report, ImuMsgs::Imu& msg) { +void ImuConverter::fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportAccelerometer report) { msg.linear_acceleration.x = report.x; msg.linear_acceleration.y = report.y; msg.linear_acceleration.z = report.z; msg.linear_acceleration_covariance = {_linear_accel_cov, 0.0, 0.0, 0.0, _linear_accel_cov, 0.0, 0.0, 0.0, _linear_accel_cov}; } -void ImuConverter::fillImuMsg(dai::IMUReportGyroscope report, ImuMsgs::Imu& msg) { +void ImuConverter::fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportGyroscope report) { msg.angular_velocity.x = report.x; msg.angular_velocity.y = report.y; msg.angular_velocity.z = report.z; msg.angular_velocity_covariance = {_angular_velocity_cov, 0.0, 0.0, 0.0, _angular_velocity_cov, 0.0, 0.0, 0.0, _angular_velocity_cov}; } -void ImuConverter::fillImuMsg(dai::IMUReportRotationVectorWAcc report, ImuMsgs::Imu& msg) { +void ImuConverter::fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportRotationVectorWAcc report) { if(_enable_rotation) { msg.orientation.x = report.i; msg.orientation.y = report.j; @@ -64,23 +66,23 @@ void ImuConverter::fillImuMsg(dai::IMUReportRotationVectorWAcc report, ImuMsgs:: } } -void ImuConverter::fillImuMsg(dai::IMUReportMagneticField report, ImuMsgs::Imu& msg) { +void ImuConverter::fillImuMsg(ImuMsgs::Imu& msg, dai::IMUReportMagneticField report) { return; } -void ImuConverter::fillImuMsg(dai::IMUReportAccelerometer report, depthai_ros_msgs::msg::ImuWithMagneticField& msg) { - fillImuMsg(report, msg.imu); +void ImuConverter::fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportAccelerometer report) { + fillImuMsg(msg.imu, report); } -void ImuConverter::fillImuMsg(dai::IMUReportGyroscope report, depthai_ros_msgs::msg::ImuWithMagneticField& msg) { - fillImuMsg(report, msg.imu); +void ImuConverter::fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportGyroscope report) { + fillImuMsg(msg.imu, report); } -void ImuConverter::fillImuMsg(dai::IMUReportRotationVectorWAcc report, depthai_ros_msgs::msg::ImuWithMagneticField& msg) { - fillImuMsg(report, msg.imu); +void ImuConverter::fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportRotationVectorWAcc report) { + fillImuMsg(msg.imu, report); } -void ImuConverter::fillImuMsg(dai::IMUReportMagneticField report, depthai_ros_msgs::msg::ImuWithMagneticField& msg) { +void ImuConverter::fillImuMsg(depthai_ros_msgs::msg::ImuWithMagneticField& msg, dai::IMUReportMagneticField report) { msg.field.magnetic_field.x = report.x; msg.field.magnetic_field.y = report.y; msg.field.magnetic_field.z = report.z; @@ -97,14 +99,19 @@ void ImuConverter::toRosMsg(std::shared_ptr inData, std::dequepackets.size(); ++i) { auto accel = inData->packets[i].acceleroMeter; auto gyro = inData->packets[i].gyroscope; + ImuMsgs::Imu msg; std::chrono::_V2::steady_clock::time_point tstamp; if(_getBaseDeviceTimestamp) tstamp = accel.getTimestampDevice(); else tstamp = accel.getTimestamp(); - - CreateUnitMessage(accel, gyro, msg, tstamp); + if(_enable_rotation) { + auto rot = inData->packets[i].rotationVector; + CreateUnitMessage(msg, tstamp, accel, gyro, rot); + } else { + CreateUnitMessage(msg, tstamp, accel, gyro); + } outImuMsgs.push_back(msg); } @@ -129,8 +136,7 @@ void ImuConverter::toRosDaiMsg(std::shared_ptr inData, std::deque< tstamp = accel.getTimestampDevice(); else tstamp = accel.getTimestamp(); - - CreateUnitMessage(accel, gyro, rot, magn, msg, tstamp); + CreateUnitMessage(msg, tstamp, accel, gyro, rot, magn); outImuMsgs.push_back(msg); } } diff --git a/depthai_ros_driver/include/depthai_ros_driver/param_handlers/imu_param_handler.hpp b/depthai_ros_driver/include/depthai_ros_driver/param_handlers/imu_param_handler.hpp index 713bf148..0045c0b4 100644 --- a/depthai_ros_driver/include/depthai_ros_driver/param_handlers/imu_param_handler.hpp +++ b/depthai_ros_driver/include/depthai_ros_driver/param_handlers/imu_param_handler.hpp @@ -5,6 +5,7 @@ #include #include "depthai/pipeline/datatype/CameraControl.hpp" +#include "depthai-shared/properties/IMUProperties.hpp" #include "depthai_bridge/ImuConverter.hpp" #include "depthai_ros_driver/param_handlers/base_param_handler.hpp" @@ -32,6 +33,7 @@ class ImuParamHandler : public BaseParamHandler { dai::CameraControl setRuntimeParams(const std::vector& params) override; std::unordered_map imuSyncMethodMap; std::unordered_map imuMessagetTypeMap; + std::unordered_map rotationVectorTypeMap; imu::ImuMsgType getMsgType(); dai::ros::ImuSyncMethod getSyncMethod(); }; diff --git a/depthai_ros_driver/include/depthai_ros_driver/param_handlers/sensor_param_handler.hpp b/depthai_ros_driver/include/depthai_ros_driver/param_handlers/sensor_param_handler.hpp index 517022de..4907c57d 100644 --- a/depthai_ros_driver/include/depthai_ros_driver/param_handlers/sensor_param_handler.hpp +++ b/depthai_ros_driver/include/depthai_ros_driver/param_handlers/sensor_param_handler.hpp @@ -27,12 +27,8 @@ class SensorParamHandler : public BaseParamHandler { explicit SensorParamHandler(rclcpp::Node* node, const std::string& name, dai::CameraBoardSocket socket); ~SensorParamHandler(); void declareCommonParams(dai::CameraBoardSocket socket); - void declareParams(std::shared_ptr monoCam, - dai_nodes::sensor_helpers::ImageSensor sensor, - bool publish); - void declareParams(std::shared_ptr colorCam, - dai_nodes::sensor_helpers::ImageSensor sensor, - bool publish); + void declareParams(std::shared_ptr monoCam, dai_nodes::sensor_helpers::ImageSensor sensor, bool publish); + void declareParams(std::shared_ptr colorCam, dai_nodes::sensor_helpers::ImageSensor sensor, bool publish); dai::CameraControl setRuntimeParams(const std::vector& params) override; private: diff --git a/depthai_ros_driver/include/depthai_ros_driver/pipeline/pipeline_generator.hpp b/depthai_ros_driver/include/depthai_ros_driver/pipeline/pipeline_generator.hpp index 9cb25266..986e7d74 100644 --- a/depthai_ros_driver/include/depthai_ros_driver/pipeline/pipeline_generator.hpp +++ b/depthai_ros_driver/include/depthai_ros_driver/pipeline/pipeline_generator.hpp @@ -32,7 +32,7 @@ class PipelineGenerator { * * @return The validated pipeline type. */ - std::string validatePipeline(rclcpp::Node* node,const std::string& typeStr, int sensorNum); + std::string validatePipeline(rclcpp::Node* node, const std::string& typeStr, int sensorNum); /** * @brief Creates the pipeline by using a plugin. Plugin types need to be of type depthai_ros_driver::pipeline_gen::BasePipeline. * diff --git a/depthai_ros_driver/src/dai_nodes/sensors/imu.cpp b/depthai_ros_driver/src/dai_nodes/sensors/imu.cpp index 78f6cc7a..db305149 100644 --- a/depthai_ros_driver/src/dai_nodes/sensors/imu.cpp +++ b/depthai_ros_driver/src/dai_nodes/sensors/imu.cpp @@ -40,6 +40,8 @@ void Imu::setupQueues(std::shared_ptr device) { auto imuMode = ph->getSyncMethod(); rclcpp::PublisherOptions options; options.qos_overriding_options = rclcpp::QosOverridingOptions(); + param_handlers::imu::ImuMsgType msgType = ph->getMsgType(); + bool enableMagn = msgType == param_handlers::imu::ImuMsgType::IMU_WITH_MAG || msgType == param_handlers::imu::ImuMsgType::IMU_WITH_MAG_SPLIT; imuConverter = std::make_unique(tfPrefix + "_frame", imuMode, ph->getParam("i_acc_cov"), @@ -47,9 +49,9 @@ void Imu::setupQueues(std::shared_ptr device) { ph->getParam("i_rot_cov"), ph->getParam("i_mag_cov"), ph->getParam("i_enable_rotation"), + enableMagn, ph->getParam("i_get_base_device_timestamp")); imuConverter->setUpdateRosBaseTimeOnToRosMsg(ph->getParam("i_update_ros_base_time_on_ros_msg")); - param_handlers::imu::ImuMsgType msgType = ph->getMsgType(); switch(msgType) { case param_handlers::imu::ImuMsgType::IMU: { rosImuPub = getROSNode()->create_publisher("~/" + getName() + "/data", 10, options); diff --git a/depthai_ros_driver/src/dai_nodes/stereo.cpp b/depthai_ros_driver/src/dai_nodes/stereo.cpp index 135de881..87cb98c3 100644 --- a/depthai_ros_driver/src/dai_nodes/stereo.cpp +++ b/depthai_ros_driver/src/dai_nodes/stereo.cpp @@ -337,10 +337,10 @@ void Stereo::closeQueues() { if(ph->getParam("i_publish_topic")) { stereoQ->close(); } - if(ph->getParam("i_publish_left_rect")){ + if(ph->getParam("i_publish_left_rect")) { leftRectQ->close(); } - if(ph->getParam("i_publish_right_rect")){ + if(ph->getParam("i_publish_right_rect")) { rightRectQ->close(); } if(ph->getParam("i_publish_synced_rect_pair")) { diff --git a/depthai_ros_driver/src/param_handlers/imu_param_handler.cpp b/depthai_ros_driver/src/param_handlers/imu_param_handler.cpp index d8593deb..f0291557 100644 --- a/depthai_ros_driver/src/param_handlers/imu_param_handler.cpp +++ b/depthai_ros_driver/src/param_handlers/imu_param_handler.cpp @@ -18,8 +18,13 @@ void ImuParamHandler::declareParams(std::shared_ptr imu, const s }; imuMessagetTypeMap = { {"IMU", imu::ImuMsgType::IMU}, {"IMU_WITH_MAG", imu::ImuMsgType::IMU_WITH_MAG}, {"IMU_WITH_MAG_SPLIT", imu::ImuMsgType::IMU_WITH_MAG_SPLIT}}; + rotationVectorTypeMap = {{"ROTATION_VECTOR", dai::IMUSensor::ROTATION_VECTOR}, + {"GAME_ROTATION_VECTOR", dai::IMUSensor::GAME_ROTATION_VECTOR}, + {"GEOMAGNETIC_ROTATION_VECTOR", dai::IMUSensor::GEOMAGNETIC_ROTATION_VECTOR}, + {"ARVR_STABILIZED_ROTATION_VECTOR", dai::IMUSensor::ARVR_STABILIZED_ROTATION_VECTOR}, + {"ARVR_STABILIZED_GAME_ROTATION_VECTOR", dai::IMUSensor::ARVR_STABILIZED_GAME_ROTATION_VECTOR}}; declareAndLogParam("i_get_base_device_timestamp", false); - declareAndLogParam("i_message_type", "IMU"); + auto messageType = declareAndLogParam("i_message_type", "IMU"); declareAndLogParam("i_sync_method", "LINEAR_INTERPOLATE_ACCEL"); declareAndLogParam("i_acc_cov", 0.0); declareAndLogParam("i_gyro_cov", 0.0); @@ -29,8 +34,13 @@ void ImuParamHandler::declareParams(std::shared_ptr imu, const s bool rotationAvailable = imuType == "BNO086"; if(declareAndLogParam("i_enable_rotation", false)) { if(rotationAvailable) { - imu->enableIMUSensor(dai::IMUSensor::ROTATION_VECTOR, declareAndLogParam("i_rot_freq", 400)); - imu->enableIMUSensor(dai::IMUSensor::MAGNETOMETER_CALIBRATED, declareAndLogParam("i_mag_freq", 100)); + auto rotationVecType = utils::getValFromMap(utils::getUpperCaseStr(declareAndLogParam("i_rotation_vector_type", "ROTATION_VECTOR")), + rotationVectorTypeMap); + imu->enableIMUSensor(rotationVecType, declareAndLogParam("i_rot_freq", 400)); + // if imu message type is IMU_WITH_MAG or IMU_WITH_MAG_SPLIT, enable magnetometer + if(messageType == "IMU_WITH_MAG" || messageType == "IMU_WITH_MAG_SPLIT") { + imu->enableIMUSensor(dai::IMUSensor::MAGNETOMETER_CALIBRATED, declareAndLogParam("i_mag_freq", 100)); + } } else { RCLCPP_ERROR(getROSNode()->get_logger(), "Rotation enabled but not available with current sensor"); declareAndLogParam("i_enable_rotation", false, true);