Skip to content

File plugin.cpp

File List > plugins > zed > plugin.cpp

Go to the documentation of this file

#include "plugin.hpp"

#include "illixr/error_util.hpp"

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace ILLIXR;
using namespace ILLIXR::data_format;

#ifdef HAND_TRACKING_CONFIG
constexpr int EXPOSURE_TIME_PERCENT = 30;
#else
constexpr int EXPOSURE_TIME_PERCENT = 8;
#endif

const record_header __imu_cam_record{"imu_cam",
                                     {
                                         {"iteration_no", typeid(std::size_t)},
                                         {"has_camera", typeid(bool)},
                                     }};

std::shared_ptr<zed_camera> zed_imu_thread::start_camera() {
    std::shared_ptr<zed_camera> zed_cam = std::make_shared<zed_camera>(switchboard_);
    bool                        with_hand_tracking;
#ifdef HAND_TRACKING_CONFIG
    with_hand_tracking = true;
#else
    with_hand_tracking = false;
#endif
    assert(zed_cam != nullptr && "Zed camera should be initialized");

    // Cam setup
    sl::InitParameters init_params;
    init_params.camera_resolution   = (with_hand_tracking) ? sl::RESOLUTION::HD720 : sl::RESOLUTION::VGA;
    init_params.coordinate_units    = (with_hand_tracking) ? sl::UNIT::UNITS : sl::UNIT::MILLIMETER; // For scene reconstruction
    init_params.coordinate_system   = (with_hand_tracking)
          ? sl::COORDINATE_SYSTEM::RIGHT_HANDED_Y_UP
          : sl::COORDINATE_SYSTEM::RIGHT_HANDED_Z_UP_X_FWD; // Coordinate system used in ROS
    init_params.camera_fps          = 30;                   // gives the best user experience
    init_params.depth_mode          = (with_hand_tracking) ? sl::DEPTH_MODE::QUALITY : sl::DEPTH_MODE::PERFORMANCE;
    init_params.depth_stabilization = true;
    init_params.depth_minimum_distance = 0.3;

    // Open the camera
    sl::ERROR_CODE err = zed_cam->open(init_params);
    if (err != sl::ERROR_CODE::SUCCESS) {
        spdlog::get("illixr")->error("[zed] {}", toString(err).c_str());
        throw std::runtime_error("ZED camera could not be initialized");
    }
    zed_cam->setCameraSettings(sl::VIDEO_SETTINGS::EXPOSURE, EXPOSURE_TIME_PERCENT);
    return zed_cam;
}

void zed_imu_thread::stop() {
    camera_thread_.stop();
    threadloop::stop();
}

zed_imu_thread::zed_imu_thread(const std::string& name_, phonebook* pb_)
    : threadloop{name_, pb_}
    , switchboard_{phonebook_->lookup_impl<switchboard>()}
    , zed_cam_{start_camera()}
    , camera_thread_{"zed_camera_thread", pb_, zed_cam_}
    , clock_{phonebook_->lookup_impl<relative_clock>()}
    , imu_{switchboard_->get_writer<imu_type>("imu")}
    , cam_reader_{switchboard_->get_reader<cam_type_zed>("cam_zed")}
    , cam_publisher_{switchboard_->get_writer<binocular_cam_type>("cam")}
    , rgb_depth_{switchboard_->get_writer<rgb_depth_type>("rgb_depth")}
    , cam_conf_pub_{switchboard_->get_writer<camera_data>("cam_data")}
    , it_log_{record_logger_} { }

// destructor
zed_imu_thread::~zed_imu_thread() {
    zed_cam_->close();
}

void zed_imu_thread::start() {
    camera_thread_.start();
    threadloop::start();
    cam_conf_pub_.put(cam_conf_pub_.allocate<camera_data>(camera_data{zed_cam_->get_config()}));
}

threadloop::skip_option zed_imu_thread::_p_should_skip() {
    zed_cam_->getSensorsData(sensors_data_, sl::TIME_REFERENCE::CURRENT);
    if (sensors_data_.imu.timestamp > last_imu_ts_) {
        std::this_thread::sleep_for(std::chrono::milliseconds{2});
        return skip_option::run;
    } else {
        return skip_option::skip_and_yield;
    }
}

void zed_imu_thread::_p_one_iteration() {
    RAC_ERRNO_MSG("zed at start of _p_one_iteration");
    // std::cout << "IMU Rate: " << sensors_data.imu.effective_rate << "\n" << std::endl;

    // Time as ullong (nanoseconds)
    auto imu_time = static_cast<ullong>(sensors_data_.imu.timestamp.getNanoseconds());

    // Time as time_point
    if (!first_imu_time_) {
        first_imu_time_  = imu_time;
        first_real_time_ = clock_->now();
    }
    // _m_first_real_time is the time point when the system receives the first IMU sample
    // Timestamp for later IMU samples is its dataset time difference from the first sample added to _m_first_real_time
    time_point imu_time_point{*first_real_time_ + std::chrono::nanoseconds(imu_time - *first_imu_time_)};

    // Linear Acceleration and Angular Velocity (av converted from deg/s to rad/s)
    Eigen::Vector3f la = {sensors_data_.imu.linear_acceleration_uncalibrated.x,
                          sensors_data_.imu.linear_acceleration_uncalibrated.y,
                          sensors_data_.imu.linear_acceleration_uncalibrated.z};
    Eigen::Vector3f av = {static_cast<float>(sensors_data_.imu.angular_velocity_uncalibrated.x * (M_PI / 180)),
                          static_cast<float>(sensors_data_.imu.angular_velocity_uncalibrated.y * (M_PI / 180)),
                          static_cast<float>(sensors_data_.imu.angular_velocity_uncalibrated.z * (M_PI / 180))};

    imu_.put(imu_.allocate<imu_type>({imu_time_point, av.cast<double>(), la.cast<double>()}));

    switchboard::ptr<const cam_type_zed> c = cam_reader_.get_ro_nullable();
    if (c && c->serial_no != last_serial_no_) {
        cv::Mat left_gray, right_gray;
        cv::cvtColor(c->at(image::LEFT_EYE), left_gray, cv::COLOR_RGB2GRAY);
        cv::cvtColor(c->at(image::RIGHT_EYE), right_gray, cv::COLOR_RGB2GRAY);
        cam_publisher_.put(
            cam_publisher_.allocate<binocular_cam_type>({imu_time_point, cv::Mat{left_gray}, cv::Mat{right_gray}}));
        rgb_depth_.put(
            rgb_depth_.allocate<rgb_depth_type>({imu_time_point, cv::Mat{c->at(image::RGB)}, cv::Mat{c->at(image::DEPTH)}}));
        last_serial_no_ = c->serial_no;
    }

    last_imu_ts_.setNanoseconds(sensors_data_.imu.timestamp.getNanoseconds());

    RAC_ERRNO_MSG("zed_imu at end of _p_one_iteration");
}

// This line makes the plugin importable by Spindle
PLUGIN_MAIN(zed_imu_thread)