11#include <iCub/CamCalibModule.h>
12#include <yarp/math/Math.h>
13#include <yarp/os/Stamp.h>
15#define AERONAUTIC_CONVENTION 0
19using namespace yarp::os;
20using namespace yarp::math;
21using namespace yarp::sig;
47 portImgOut=_portImgOut;
56void CamCalibPort::onRead(ImageOf<PixelRgb> &yrpImgIn)
62 double time = s.getTime();
64 if (!updatePose(
time)) {
68 unsigned char *pixel = yrpImgIn.getPixelAddress(0, 0);
69 double *stamp =
reinterpret_cast<double*
>(pixel);
70 double backdoorTime = stamp[0];
71 double backdoorRoll = stamp[1];
72 double backdoorPitch = stamp[2];
73 double backdoorYaw = stamp[3];
75 if (
time != backdoorTime) {
76 yWarning() <<
"Backdoor time:" << backdoorTime <<
"Imu time:" <<
time <<
"diff:" << (backdoorTime -
time);
84 b.addFloat64(backdoorRoll);
85 b.addFloat64(backdoorPitch);
86 b.addFloat64(backdoorYaw);
87 b.addFloat64(backdoorRoll - roll);
88 b.addFloat64(backdoorPitch - pitch);
89 b.addFloat64(backdoorYaw - yaw);
95 if (portImgOut!=NULL) {
96 yarp::sig::ImageOf<PixelRgb> &yrpImgOut=portImgOut->prepare();
99 yDebug(
"received input image after %g [s] ... ",t-t0);
102 double t1=Time::now();
104 if (calibTool!=NULL) {
105 calibTool->
apply(yrpImgIn,yrpImgOut);
107 for (
int r =0; r <yrpImgOut.height(); r++) {
108 for (
int c=0; c<yrpImgOut.width(); c++) {
109 unsigned char *pixel = yrpImgOut.getPixelAddress(c,r);
110 double mean = (1.0/3.0)*(pixel[0]+pixel[1]+pixel[2]);
112 for(
int i=0; i<3; i++) {
113 double s=pixel[i]-mean;
122 pixel[i]=(
unsigned char)sn;
128 yDebug(
"calibrated in %g [s]\n",Time::now()-t1);
133 yDebug(
"just copied in %g [s]\n",Time::now()-t1);
136 lock_guard<mutex> lck(m);
145 std::snprintf(buf, 512,
"%d %.*g %.*g %.*g %.*g", s.getCount(), DBL_DIG, s.getTime(), DBL_DIG, roll, DBL_DIG, pitch, DBL_DIG, yaw);
146 pose.fromString(buf);
147 portImgOut->setEnvelope(pose);
149 portImgOut->writeStrict();
157bool CamCalibPort::selectBottleFromMap(
double time,
158 std::map<double, yarp::os::Bottle> *datamap,
159 yarp::os::Bottle *bottle,
162 if (datamap->size() == 0) {
168 lock_guard<mutex> lck(m);
172 bottle->addFloat64(m_last_imu.get(6).asFloat64());
173 bottle->addFloat64(m_last_imu.get(7).asFloat64());
174 bottle->addFloat64(m_last_imu.get(8).asFloat64());
178 bottle->addFloat64(m_last_h_encs.get(0).asFloat64());
179 bottle->addFloat64(m_last_h_encs.get(1).asFloat64());
180 bottle->addFloat64(m_last_h_encs.get(2).asFloat64());
187 std::map<double, yarp::os::Bottle>::iterator it_prev, it_next;
190 it_next = datamap->lower_bound(
time);
194 while (it_next == datamap->end() || it_next->first <
time)
198 yarp::os::Time::delay(0.001);
201 yWarning() <<
"Clock out of sync, check your NTPD settings";
205 it_next = datamap->lower_bound(
time);
209 if(it_prev != datamap->begin()) {
212 if(it_next == datamap->end() && it_next != datamap->begin()) {
216 double diff_prev =
time - it_prev->first;
217 double diff_next = it_next->first -
time;
218 double diff = (diff_prev >= diff_next) ? diff_next : diff_prev;
221 std::map<double, yarp::os::Bottle>::iterator it_begin, it_end;
223 it_end = datamap->end();
224 if(it_end != datamap->begin()) {
227 it_begin = datamap->begin();
231 for(std::map<double, yarp::os::Bottle>::iterator it = datamap->begin(); it != datamap->end(); ++it) {
232 if (it->first >
time) {
239 double diff_end = it_end->first -
time;
240 double diff_begin =
time - it_begin->first;
241 bool err_prev = ((diff_prev >= 0.0025) || (diff_prev <= -0.0025));
242 bool warn_prev = ((diff_prev >= 0.0015) || (diff_prev <= -0.0015));
243 bool err_next = ((diff_next >= 0.0025) || (diff_next <= -0.0025));
244 bool warn_next = ((diff_next >= 0.0015) || (diff_next <= -0.0015));
245 bool err_end = ((diff_end >= 0.0025) || (diff_end <= -0.0025));
246 bool warn_end = ((diff_end >= 0.0015) || (diff_end <= -0.0015));
247 bool err_begin = ((diff_begin >= 0.0025) || (diff_begin <= -0.0025));
248 bool warn_begin = ((diff_begin >= 0.0015) || (diff_begin <= -0.0015));
249 bool err = ((diff >= 0.0025) || (diff <= -0.0025));
250 bool warn = ((diff >= 0.0015) || (diff <= -0.0015));
252 printf(
"%f, %f, %s%f%s, %d, %f, %s%f%s, %f, %s%f%s, %f, %s%f%s, %d, %s%f%s, %s%zd%s %s\n",
255 (err_begin ?
"\033[0;31m" : (warn_begin ?
"\033[0;33m" :
"")), diff_begin, ((err_begin||warn_begin) ?
"\033[0m" :
""),
258 (err_prev ?
"\033[0;31m" : (warn_prev ?
"\033[0;33m" :
"")), diff_prev, ((err_prev||warn_prev) ?
"\033[0m" :
""),
260 (err_next ?
"\033[0;31m" : (warn_next ?
"\033[0;33m" :
"")), diff_next, ((err_next||warn_next) ?
"\033[0m" :
""),
262 (err_end ?
"\033[0;31m" : (warn_end ?
"\033[0;33m" :
"")), diff_end, ((err_end||warn_end) ?
"\033[0m" :
""),
264 (err ?
"\033[0;31m" : (warn ?
"\033[0;33m" :
"")), diff, ((err||warn) ?
"\033[0m" :
""),
265 ((datamap->size() <= 10) ?
"\033[0;31m" : ((datamap->size() <= 15) ?
"\033[0;33m" :
"")), datamap->size(), ((datamap->size() <= 15) ?
"\033[0m" :
""),
266 ((diff > maxDelay) ?
"\033[0;31mSKIPPED\033[0m" :
"OK"));
273 yDebug() <<
"maxDelay (" << maxDelay <<
") exceeded";
280 for(
int i = 0; i < it_prev->second.size(); ++i) {
282 double x0 = it_prev->second.get(i).asFloat64();
283 double x1 = it_next->second.get(i).asFloat64();
284 double t0 = it_prev->first;
285 double t1 = it_next->first;
291 xx = x0 + (tx - t0)*(
x1 - x0)/(t1 - t0);
294 double v0 = it_prev->second.get(i+6).asFloat64();
295 double v1 = it_next->second.get(i+6).asFloat64();
296 double a = (v1 - v0) / (t1 - t0);
298 if (fabs(v1 - v0) > 30) {
304 xx = x0 + (tx - t0) * v0;
323 bottle->addFloat64(xx);
325 bottle->add(it_prev->second.get(i));
330 if (it_prev != datamap->begin()) {
331 datamap->erase(datamap->begin(), it_prev);
339bool CamCalibPort::updatePose(
double time)
342 if (!selectBottleFromMap(
time, &m_h_encs_map, &m_curr_h_encs, verbose && !useIMU)) {
349 if (!selectBottleFromMap(
time, &m_t_encs_map, &m_curr_t_encs, verbose && !useIMU)) {
350 if (!useIMU && useTorso) {
356 if (!selectBottleFromMap(
time, &m_imu_map, &m_curr_imu, verbose && useIMU)) {
362 double tix = useTorso ? m_curr_t_encs.get(1).asFloat64()/180.0*
M_PI : 0;
363 double tiy = useTorso ? -m_curr_t_encs.get(2).asFloat64()/180.0*
M_PI : 0;
364 double tiz = useTorso ? -m_curr_t_encs.get(0).asFloat64()/180.0*
M_PI : 0;
366 double nix = -m_curr_h_encs.get(1).asFloat64()/180.0*
M_PI;
367 double niy = m_curr_h_encs.get(0).asFloat64()/180.0*
M_PI;
368 double niz = m_curr_h_encs.get(2).asFloat64()/180.0*
M_PI;
370 double t = useEyes ? m_curr_h_encs.get(3).asFloat64()/180.0*
M_PI : 0;
371 double vs = useEyes ? m_curr_h_encs.get(4).asFloat64()/180.0*
M_PI : 0;
372 double vg = useEyes ? m_curr_h_encs.get(5).asFloat64()/180.0*
M_PI : 0;
374 double imu_x = useIMU ? m_curr_imu.get(0).asFloat64()/180.0*
M_PI : 0;
375 double imu_y = useIMU ? m_curr_imu.get(1).asFloat64()/180.0*
M_PI : 0;
376 double imu_z = useIMU ? m_curr_imu.get(2).asFloat64()/180.0*
M_PI : 0;
380 yarp::sig::Vector torso_roll_vector(3);
381 torso_roll_vector(0) = tix;
382 torso_roll_vector(1) = 0;
383 torso_roll_vector(2) = 0;
384 yarp::sig::Matrix torso_roll_dcm = yarp::math::rpy2dcm(torso_roll_vector);
386 yarp::sig::Vector torso_pitch_vector(3);
387 torso_pitch_vector(0) = 0;
388 torso_pitch_vector(1) = tiy;
389 torso_pitch_vector(2) = 0;
390 yarp::sig::Matrix torso_pitch_dcm = yarp::math::rpy2dcm(torso_pitch_vector);
392 yarp::sig::Vector torso_yaw_vector(3);
393 torso_yaw_vector(0) = 0;
394 torso_yaw_vector(1) = 0;
395 torso_yaw_vector(2) = tiz;
396 yarp::sig::Matrix torso_yaw_dcm = yarp::math::rpy2dcm(torso_yaw_vector);
398 yarp::sig::Matrix torso_dcm = (torso_pitch_dcm * torso_roll_dcm) * torso_yaw_dcm;
402 yarp::sig::Vector neck_roll_vector(3);
403 neck_roll_vector(0) = nix;
404 neck_roll_vector(1) = 0;
405 neck_roll_vector(2) = 0;
406 yarp::sig::Matrix neck_roll_dcm = yarp::math::rpy2dcm(neck_roll_vector);
408 yarp::sig::Vector neck_pitch_vector(3);
409 neck_pitch_vector(0) = 0;
410 neck_pitch_vector(1) = niy;
411 neck_pitch_vector(2) = 0;
412 yarp::sig::Matrix neck_pitch_dcm = yarp::math::rpy2dcm(neck_pitch_vector);
414 yarp::sig::Vector neck_yaw_vector(3);
415 neck_yaw_vector(0) = 0;
416 neck_yaw_vector(1) = 0;
417 neck_yaw_vector(2) = niz;
418 yarp::sig::Matrix neck_yaw_dcm = yarp::math::rpy2dcm(neck_yaw_vector);
420 yarp::sig::Matrix neck_dcm = (neck_pitch_dcm * neck_roll_dcm) * neck_yaw_dcm;
424 yarp::sig::Vector eye_pitch_vector(3);
425 eye_pitch_vector(0) = 0;
426 eye_pitch_vector(1) = t;
427 eye_pitch_vector(2) = 0;
428 yarp::sig::Matrix eye_pitch_dcm = yarp::math::rpy2dcm(eye_pitch_vector);
430 yarp::sig::Vector eye_yaw_vector(3);
431 eye_yaw_vector(0) = 0;
432 eye_yaw_vector(1) = 0;
433 eye_yaw_vector(2) = 0;
435 eye_yaw_vector(2) = -(vs + vg/2);
437 eye_yaw_vector(2) = -(vs - vg / 2);
439 yarp::sig::Matrix eye_yaw_dcm = yarp::math::rpy2dcm(eye_yaw_vector);
441 yarp::sig::Matrix eye_dcm = eye_pitch_dcm * eye_yaw_dcm;
445 yarp::sig::Matrix encoders_dcm = (torso_dcm * neck_dcm) * eye_dcm;
446 yarp::sig::Vector encoders_rpy = yarp::math::dcm2rpy(encoders_dcm);
450 yarp::sig::Vector imu_roll_vector(3);
451 imu_roll_vector(0) = imu_x;
452 imu_roll_vector(1) = 0;
453 imu_roll_vector(2) = 0;
454 yarp::sig::Matrix imu_roll_dcm = yarp::math::rpy2dcm(imu_roll_vector);
456 yarp::sig::Vector imu_pitch_vector(3);
457 imu_pitch_vector(0) = 0;
458 imu_pitch_vector(1) = imu_y;
459 imu_pitch_vector(2) = 0;
460 yarp::sig::Matrix imu_pitch_dcm = yarp::math::rpy2dcm(imu_pitch_vector);
462 yarp::sig::Vector imu_yaw_vector(3);
463 imu_yaw_vector(0) = 0;
464 imu_yaw_vector(1) = 0;
465 imu_yaw_vector(2) = imu_z;
466 yarp::sig::Matrix imu_yaw_dcm = yarp::math::rpy2dcm(imu_yaw_vector);
468#if AERONAUTIC_CONVENTION
470 yarp::sig::Matrix imu_dcm = (imu_yaw_dcm * imu_roll_dcm) * imu_pitch_dcm;
473 yarp::sig::Matrix imu_dcm = (imu_yaw_dcm * imu_pitch_dcm) * imu_roll_dcm;
476 yarp::sig::Vector imu_rpy = yarp::math::dcm2rpy(imu_dcm);
479 roll = encoders_rpy(0) * 180.0/
M_PI;
480 pitch = encoders_rpy(1) * 180.0/
M_PI;
481 yaw = encoders_rpy(2) * 180.0/
M_PI;
483 roll = imu_rpy(0) * 180.0/
M_PI;
484 pitch = imu_rpy(1) * 180.0/
M_PI;
485 yaw = imu_rpy(2) * 180.0/
M_PI;
530 string str = rf.check(
"name", Value(
"/camCalib"),
"module name (string)").asString();
531 setName(str.c_str());
533 double maxDelay = rf.check(
"maxDelay", Value(0.010),
"Max delay between image and encoders").asFloat64();
536 Bottle botConfig(rf.toString());
539 if(botConfig.check(
"group", valGroup,
"Configuration group to load module options from (string).")) {
540 strGroup = valGroup->asString();
542 if (botConfig.check(strGroup)){
543 Bottle &group=botConfig.findGroup(strGroup,
"Loading configuration from group " + strGroup);
544 botConfig.fromString(group.toString());
546 yError() <<
"Group " << strGroup <<
" not found.";
550 yError (
"There seem to be an error loading parameters (group section missing), stopping module");
554 string calibToolName = botConfig.check(
"projection",
556 "Projection/mapping applied to calibrated image [projection|spherical] (string).").asString();
559 if (_calibTool!=NULL) {
560 bool ok = _calibTool->
open(botConfig);
568 if (yarp::os::Network::exists(getName(
"/in"))) {
569 yWarning() <<
"port " << getName(
"/in") <<
" already in use";
571 if (yarp::os::Network::exists(getName(
"/out"))) {
572 yWarning() <<
"port " << getName(
"/out") <<
" already in use";
574 if (yarp::os::Network::exists(getName(
"/conf"))) {
575 yWarning() <<
"port " << getName(
"/conf") <<
" already in use";
577 _prtImgIn.
setSaturation(rf.check(
"saturation",Value(1.0)).asFloat64());
578 _prtImgIn.open(getName(
"/in"));
581 _prtImgIn.
setLeftEye((strGroup ==
"CAMERA_CALIBRATION_LEFT") ?
true : false);
587 _prtImgIn.useCallback();
588 _prtImgOut.open(getName(
"/out"));
589 _configPort.open(getName(
"/conf"));
591 _prtTEncsIn.open(getName(
"/torso_encs/in"));
594 _prtTEncsIn.useCallback();
596 _prtHEncsIn.open(getName(
"/head_encs/in"));
599 _prtHEncsIn.useCallback();
601 _prtImuIn.open(getName(
"/imu/in"));
604 _prtImuIn.useCallback();
609 _prtImgIn.
rpyPort.open(getName(
"/rpy"));
622 if (_calibTool != NULL){
632 _prtImgIn.interrupt();
633 _prtImgOut.interrupt();
634 _configPort.interrupt();
635 _prtTEncsIn.interrupt();
636 _prtHEncsIn.interrupt();
637 _prtImuIn.interrupt();
641void TorsoEncoderPort::onRead(yarp::os::Bottle &t_encs)
644 this->getEnvelope(s);
645 double time = s.getTime();
651void HeadEncoderPort::onRead(yarp::os::Bottle &h_encs)
654 this->getEnvelope(s);
655 double time = s.getTime();
661void ImuPort::onRead(yarp::os::Bottle &imu)
664 this->getEnvelope(s);
665 double time = s.getTime();
685 if (command.get(0).asString()==
"quit") {
686 reply.addString(
"quitting");
688 }
else if (command.get(0).asString()==
"sat" || command.get(0).asString()==
"saturation") {
689 double satVal = command.get(1).asFloat64();
692 reply.addString(
"ok");
693 }
else if (command.get(0).asString()==
"filt") {
695 }
else if (command.get(0).asString()==
"cf1") {
696 _prtImgIn.
cf1 = command.get(1).asFloat64();
697 }
else if (command.get(0).asString()==
"cf2") {
698 _prtImgIn.
cf2 = command.get(1).asFloat64();
700 yError() <<
"command not known - type help for more info";
virtual bool interruptModule()
virtual bool respond(const yarp::os::Bottle &command, yarp::os::Bottle &reply)
virtual bool configure(yarp::os::ResourceFinder &rf)
Passes config on to CalibTool.
virtual bool updateModule()
virtual double getPeriod()
void setUseLast(bool useLast)
yarp::os::BufferedPort< yarp::os::Bottle > rpyPort
void setLeftEye(bool eye)
void setUseIMU(bool useIMU)
void setSaturation(double satVal)
void setTorsoEncoders(double time, const yarp::os::Bottle &t_encs)
void setUseTorso(bool useTorso)
void setImuData(double time, const yarp::os::Bottle &imu)
void setVerbose(const bool sw)
void setUseEyes(bool useEyes)
void setPointers(yarp::os::BufferedPort< yarp::sig::ImageOf< yarp::sig::PixelRgb > > *_portImgOut, ICalibTool *_calibTool)
void setHeadEncoders(double time, const yarp::os::Bottle &h_encs)
void setMaxDelay(double delay)