8#include <RobotsIO/Camera/iCubCamera.h>
12#include <unsupported/Eigen/MatrixFunctions>
14#include <yarp/cv/Cv.h>
15#include <yarp/eigen/Eigen.h>
16#include <yarp/os/LogStream.h>
17#include <yarp/os/Property.h>
18#include <yarp/os/ResourceFinder.h>
19#include <yarp/sig/Image.h>
22using namespace RobotsIO::Camera;
23using namespace iCub::iKin;
24using namespace yarp::cv;
25using namespace yarp::eigen;
26using namespace yarp::os;
27using namespace yarp::sig;
32 const std::string& robot_name,
33 const std::string& laterality,
34 const std::string& port_prefix,
35 const bool& use_calibration,
36 const std::string& calibration_path
38 laterality_(laterality),
39 use_calibration_(use_calibration)
42 if (!yarp_.checkNetwork())
44 throw(std::runtime_error(log_name_ +
"::ctor. Error: YARP network is not available."));
48 if ((laterality_ !=
"left") && (laterality_ !=
"right"))
50 std::string err = log_name_ +
"::ctor. Please use a valid laterality when constructing the iCubCamera instance.";
51 throw(std::runtime_error(err));
56 properties.put(
"device",
"gazecontrollerclient");
57 properties.put(
"remote",
"/iKinGazeCtrl");
58 properties.put(
"local",
"/" + port_prefix +
"/gazecontroller");
61 bool ok = driver_gaze_.open(properties) && driver_gaze_.view(gaze_control_) && (gaze_control_ !=
nullptr);
68 gaze_control_->getInfo(info);
70 key =
"camera_width_" + laterality_;
71 if (info.find(key).isNull())
73 std::string err = log_name_ +
"::ctor. Error: cannot load iCub " + laterality_ +
" camera width.";
74 throw(std::runtime_error(err));
76 parameters_.width(info.find(key).asInt32());
78 key =
"camera_height_" + laterality_;
79 if (info.find(key).isNull())
81 std::string err = log_name_ +
"::ctor. Error: cannot load iCub " + laterality_ +
" camera height.";
82 throw(std::runtime_error(err));
84 parameters_.height(info.find(key).asInt32());
86 key =
"camera_intrinsics_" + laterality_;
87 if (info.find(key).isNull())
89 std::string err = log_name_ +
"::ctor. Error: cannot load iCub " + laterality_ +
" camera intrinsic parameters.";
90 throw(std::runtime_error(err));
92 Bottle *list = info.find(key).asList();
93 parameters_.fx(list->get(0).asFloat64());
94 parameters_.cx(list->get(2).asFloat64());
95 parameters_.fy(list->get(5).asFloat64());
96 parameters_.cy(list->get(6).asFloat64());
98 parameters_.initialized(
true);
103 use_driver_gaze_ =
false;
106 parameters_.width(640);
107 parameters_.height(480);
108 if (laterality_ ==
"left")
110 parameters_.fx(468.672);
111 parameters_.cx(323.045);
112 parameters_.fy(467.73);
113 parameters_.cy(245.784);
117 parameters_.fx(468.488);
118 parameters_.cx(301.274);
119 parameters_.fy(467.427);
120 parameters_.cy(245.503);
122 parameters_.initialized(
true);
126 properties.put(
"device",
"remote_controlboard");
127 properties.put(
"local",
"/" + port_prefix +
"/torso:i");
128 properties.put(
"remote",
"/" + robot_name +
"/torso");
129 ok = drv_torso_.open(properties) && drv_torso_.view(itorso_) && (itorso_ !=
nullptr);
132 std::string err = log_name_ +
"::ctor. Error: cannot open remote control board for torso.";
133 throw(std::runtime_error(err));
137 left_eye_kinematics_ = iCubEye(
"left_v2");
138 right_eye_kinematics_ = iCubEye(
"right_v2");
140 left_eye_kinematics_.setAllConstraints(
false);
141 right_eye_kinematics_.setAllConstraints(
false);
143 left_eye_kinematics_.releaseLink(0);
144 left_eye_kinematics_.releaseLink(1);
145 left_eye_kinematics_.releaseLink(2);
146 right_eye_kinematics_.releaseLink(0);
147 right_eye_kinematics_.releaseLink(1);
148 right_eye_kinematics_.releaseLink(2);
153 properties.put(
"device",
"remote_controlboard");
154 properties.put(
"local",
"/" + port_prefix +
"/head:i");
155 properties.put(
"remote",
"/" + robot_name +
"/head");
156 ok = drv_head_.open(properties) && drv_head_.view(ihead_) && (ihead_ !=
nullptr);
159 std::string err = log_name_ +
"::ctor. Error: cannot open remote control board for head.";
160 throw(std::runtime_error(err));
164 if (use_calibration_)
165 if (!load_calibration_model(calibration_path))
167 std::string err = log_name_ +
"::ctor. Error: cannot load calibration model.";
168 throw(std::runtime_error(err));
172 if (!(port_rgb_.open(
"/" + port_prefix +
"/rgb:i")))
174 std::string err = log_name_ +
"::ctor. Error: cannot open rgb input port.";
175 throw(std::runtime_error(err));
179 if (!(port_depth_.open(
"/" + port_prefix +
"/depth:i")))
181 std::string err = log_name_ +
"::ctor. Error: cannot open depth input port.";
182 throw(std::runtime_error(err));
185 Camera::initialize();
188 std::cout << log_name_ +
"::ctor. Camera parameters:" << std::endl;
189 std::cout << log_name_ +
" - width: " << parameters_.width() << std::endl;
190 std::cout << log_name_ +
" - height: " << parameters_.height() << std::endl;
191 std::cout << log_name_ +
" - fx: " << parameters_.fx() << std::endl;
192 std::cout << log_name_ +
" - fy: " << parameters_.fy() << std::endl;
193 std::cout << log_name_ +
" - cx: " << parameters_.cx() << std::endl;
194 std::cout << log_name_ +
" - cy: " << parameters_.cy() << std::endl;
198iCubCamera::iCubCamera
200 const std::string& data_path,
201 const std::string& laterality,
202 const std::size_t& width,
203 const size_t& height,
208 const bool& load_encoders_data,
209 const bool& use_calibration,
210 const std::string& calibration_path
212 Camera(data_path, width, height, fx, cx, fy, cy),
213 laterality_(laterality),
214 load_encoders_data_(load_encoders_data),
215 use_calibration_(use_calibration)
218 if (use_calibration_)
219 if (!load_calibration_model(calibration_path))
221 std::string err = log_name_ +
"::ctor. Error: cannot load calibration model.";
222 throw(std::runtime_error(err));
225 Camera::initialize();
229iCubCamera::~iCubCamera()
232 if (use_driver_gaze_)
233 driver_gaze_.close();
249 return use_driver_gaze_;
253yarp::dev::IGazeControl& iCubCamera::controller()
255 return *gaze_control_;
264 ImageOf<PixelFloat>* image_in;
265 image_in = port_depth_.read(blocking);
267 if (image_in ==
nullptr)
268 return std::make_pair(
false, MatrixXf());
271 port_depth_.getEnvelope(stamp);
272 time_stamp_depth_ = stamp.getTime();
273 is_time_stamp_depth_ =
true;
275 cv::Mat image = yarp::cv::toCvMat(*image_in);
276 Map<Eigen::Matrix<float, Dynamic, Dynamic, Eigen::RowMajor>>
depth(image.ptr<
float>(), image.rows, image.cols);
278 return std::make_pair(
true,
depth);
282std::pair<bool, Transform<double, 3, Affine>> iCubCamera::pose(
const bool& blocking)
284 bool valid_pose =
false;
285 Transform<double, 3, Affine> pose;
288 std::tie(valid_pose, pose) = Camera::pose_offline();
290 std::tie(valid_pose, pose) = laterality_pose(laterality_, blocking);
293 return std::make_pair(
false, Transform<double, 3, Affine>());
296 if ((laterality() ==
"right") && use_calibration_)
298 bool valid_encoders_input =
false;
299 if ((ihead_ !=
nullptr) || (load_encoders_data_))
302 Eigen::VectorXd head_encoders(6);
303 std::tie(valid_encoders_input, head_encoders) =
auxiliary_data(
true);
306 if (valid_encoders_input)
308 yarp::sig::Vector input(3);
309 toEigen(input) = head_encoders.tail<3>() * M_PI / 180.0;
312 yarp::sig::Vector prediction = calibration_.predict(input).getPrediction();
315 Eigen::Transform<double, 3, Eigen::Affine> output = exp_map(yarp::eigen::toEigen(prediction));
317 pose = pose * output;
321 if (!valid_encoders_input)
322 std::cout << log_name_ +
"::pose. Warning: calibration requested, however eyes encoders cannot be retrieved." << std::endl;
325 return std::make_pair(
true, pose);
329std::pair<bool, cv::Mat> iCubCamera::rgb(
const bool& blocking)
332 return Camera::rgb_offline();
334 ImageOf<PixelRgb>* image_in;
335 image_in = port_rgb_.read(blocking);
337 if (image_in ==
nullptr)
338 return std::make_pair(
false, cv::Mat());
341 port_rgb_.getEnvelope(stamp);
342 time_stamp_rgb_ = stamp.getTime();
343 is_time_stamp_rgb_ =
true;
345 cv::Mat image = yarp::cv::toCvMat(*image_in);
347 return std::make_pair(
true, image);
351std::pair<bool, double> iCubCamera::time_stamp_rgb()
const
354 return Camera::time_stamp_rgb_offline();
356 return std::make_pair(is_time_stamp_rgb_, time_stamp_rgb_);
360std::pair<bool, double> iCubCamera::time_stamp_depth()
const
363 return Camera::time_stamp_depth_offline();
365 return std::make_pair(is_time_stamp_depth_, time_stamp_depth_);
375 if (use_driver_gaze_)
376 return std::make_pair(
false, VectorXd());
378 yarp::sig::Vector torso_encoders_(3);
379 yarp::sig::Vector head_encoders_(6);
381 if (!itorso_->getEncoders(torso_encoders_.data()))
382 return std::make_pair(
false, VectorXd());
384 if (!ihead_->getEncoders(head_encoders_.data()))
385 return std::make_pair(
false, VectorXd());
387 VectorXd encoders(9);
388 encoders.head<3>() = toEigen(torso_encoders_);
389 encoders.tail<6>() = toEigen(head_encoders_);
391 return std::make_pair(
true, encoders);
395std::size_t iCubCamera::auxiliary_data_size()
const
398 if (load_encoders_data_)
405std::string iCubCamera::laterality()
411std::pair<bool, Eigen::Transform<double, 3, Eigen::Affine>> iCubCamera::laterality_pose(
const std::string& laterality,
const bool& blocking)
413 Transform<double, 3, Affine> pose;
415 yarp::sig::Vector position_yarp;
416 yarp::sig::Vector orientation_yarp;
418 bool ok = getLateralityEyePose(laterality, position_yarp, orientation_yarp);
421 return std::make_pair(
false, Transform<double, 3, Affine>());
423 pose = Translation<double, 3>(toEigen(position_yarp));
424 pose.rotate(AngleAxisd(orientation_yarp(3), toEigen(orientation_yarp).head<3>()));
426 return std::make_pair(
true, pose);
430void iCubCamera::set_laterality(
const std::string& laterality)
432 laterality_ = laterality;
436bool iCubCamera::getLateralityEyePose(
const std::string& laterality, yarp::sig::Vector& position, yarp::sig::Vector& orientation)
438 if ((laterality !=
"left") && (laterality !=
"right"))
441 if (use_driver_gaze_)
443 if (laterality ==
"left")
444 return gaze_control_->getLeftEyePose(position, orientation);
446 return gaze_control_->getRightEyePose(position, orientation);
450 yarp::sig::Vector torso_encoders_(3);
451 yarp::sig::Vector head_encoders_(6);
453 if (!itorso_->getEncoders(torso_encoders_.data()))
456 if (!ihead_->getEncoders(head_encoders_.data()))
459 yarp::sig::Vector chain_joints(8);
460 chain_joints(0) = torso_encoders_(2);
461 chain_joints(1) = torso_encoders_(1);
462 chain_joints(2) = torso_encoders_(0);
463 chain_joints(3) = head_encoders_(0);
464 chain_joints(4) = head_encoders_(1);
465 chain_joints(5) = head_encoders_(2);
466 chain_joints(6) = head_encoders_(3);
468 double version = head_encoders_(4);
469 double vergence = head_encoders_(5);
471 if (laterality ==
"left")
472 chain_joints(7) = version + vergence / 2.0;
474 chain_joints(7) = version - vergence / 2.0;
476 yarp::sig::Vector pose;
477 if (laterality ==
"left")
478 pose = left_eye_kinematics_.EndEffPose(chain_joints * M_PI / 180.0);
480 pose = right_eye_kinematics_.EndEffPose(chain_joints * M_PI / 180.0);
483 orientation.resize(4);
484 position = pose.subVector(0, 2);
485 orientation = pose.subVector(3, 6);
492Eigen::Transform<double, 3, Eigen::Affine> iCubCamera::exp_map(
const Eigen::VectorXd& se3)
494 Eigen::Transform<double, 3, Eigen::Affine> SE3;
496 Eigen::Matrix3d log_R = Eigen::Matrix3d::Zero();
497 log_R(0, 1) = -1.0 * se3(5);
498 log_R(0, 2) = se3(4);
499 log_R(1, 0) = se3(5);
500 log_R(1, 2) = -1.0 * se3(3);
501 log_R(2, 0) = -1.0 * se3(4);
502 log_R(2, 1) = se3(3);
504 double theta = se3.tail<3>().norm() + std::numeric_limits<double>::epsilon();
505 Eigen::Matrix3d V = Eigen::Matrix3d::Identity() + (1 - std::cos(theta)) / (theta * theta) * log_R + (theta - std::sin(theta)) / (std::pow(theta, 3)) * log_R * log_R;
507 SE3 = Eigen::Translation<double, 3>(V * se3.head<3>());
508 SE3.rotate(log_R.exp());
514bool iCubCamera::load_calibration_model(
const std::string& model_path)
516 std::ifstream model_in;
517 model_in.open(model_path);
518 if (!model_in.is_open())
522 std::stringstream ss;
523 ss << model_in.rdbuf();
524 model.fromString(ss.str());
527 calibration_.readBottle(model);
virtual std::pair< bool, Eigen::MatrixXf > depth_offline()
virtual std::pair< bool, Eigen::VectorXd > auxiliary_data_offline()
std::pair< bool, Eigen::VectorXd > auxiliary_data(const bool &blocking) override
bool is_controller_available()
std::pair< bool, Eigen::MatrixXf > depth(const bool &blocking) override