00001 #include <stdexcept>
00002
00003 #include <boost/filesystem/fstream.hpp>
00004 #include <boost/format.hpp>
00005 #include <boost/scope_exit.hpp>
00006 #include <boost/version.hpp>
00007
00008 #include <dynamic_reconfigure/server.h>
00009 #include <image_proc/advertisement_checker.h>
00010 #include <image_transport/image_transport.h>
00011 #include <ros/param.h>
00012 #include <ros/ros.h>
00013 #include <ros/transport_hints.h>
00014 #include <sensor_msgs/Image.h>
00015 #include <std_msgs/String.h>
00016 #include <tf/transform_broadcaster.h>
00017
00018 #include <visp_tracker/MovingEdgeSites.h>
00019
00020 #include <boost/bind.hpp>
00021 #include <visp/vpExponentialMap.h>
00022 #include <visp/vpImage.h>
00023 #include <visp/vpImageConvert.h>
00024 #include <visp/vpCameraParameters.h>
00025 #include <visp/vpMbEdgeTracker.h>
00026
00027 #include "conversion.hh"
00028 #include "callbacks.hh"
00029 #include "file.hh"
00030 #include "names.hh"
00031
00032 #include "tracker.hh"
00033
00034
00035
00036
00037
00038 namespace visp_tracker
00039 {
00040 bool
00041 Tracker::initCallback(visp_tracker::Init::Request& req,
00042 visp_tracker::Init::Response& res)
00043 {
00044 ROS_INFO("Initialization request received.");
00045
00046 res.initialization_succeed = false;
00047
00048
00049 BOOST_SCOPE_EXIT((&res)(&tracker_)(&state_)
00050 (&lastTrackedImage_))
00051 {
00052 if(!res.initialization_succeed)
00053 {
00054 tracker_.resetTracker();
00055 state_ = WAITING_FOR_INITIALIZATION;
00056 lastTrackedImage_ = 0;
00057 }
00058 } BOOST_SCOPE_EXIT_END;
00059
00060 std::string fullModelPath;
00061 boost::filesystem::ofstream modelStream;
00062
00063
00064 if (!makeModelFile(modelStream, fullModelPath))
00065 return true;
00066
00067
00068 vpMe movingEdge;
00069 convertInitRequestToVpMe(req, tracker_, movingEdge);
00070
00071
00072 visp_tracker::MovingEdgeConfig config;
00073 convertVpMeToMovingEdgeConfig(movingEdge, tracker_, config);
00074 reconfigureSrv_.updateConfig(config);
00075
00076
00077 movingEdge.initMask();
00078
00079
00080 tracker_.resetTracker();
00081 state_ = WAITING_FOR_INITIALIZATION;
00082 lastTrackedImage_ = 0;
00083
00084 tracker_.setMovingEdge(movingEdge);
00085
00086
00087 try
00088 {
00089 ROS_DEBUG_STREAM("Trying to load the model: " << fullModelPath);
00090 tracker_.loadModel(fullModelPath.c_str());
00091 modelStream.close();
00092 }
00093 catch(...)
00094 {
00095 ROS_ERROR_STREAM("Failed to load the model: " << fullModelPath);
00096 return true;
00097 }
00098 ROS_DEBUG("Model has been successfully loaded.");
00099
00100
00101 transformToVpHomogeneousMatrix(cMo_, req.initial_cMo);
00102
00103
00104 ROS_INFO_STREAM("Initializing tracker with cMo:\n" << cMo_);
00105 try
00106 {
00107 tracker_.init(image_, cMo_);
00108 ROS_INFO("Tracker successfully initialized.");
00109
00110 movingEdge.print();
00111 }
00112 catch(const std::string& str)
00113 {
00114 ROS_ERROR_STREAM("Tracker initialization has failed: " << str);
00115 }
00116
00117
00118 res.initialization_succeed = true;
00119 state_ = TRACKING;
00120 return true;
00121 }
00122
00123 void
00124 Tracker::cameraVelocityCallback(const geometry_msgs::TwistStampedConstPtr&
00125 stampedTwist)
00126 {
00127
00128 if(!velocities_.empty())
00129 {
00130 const velocityDuringInterval_t& newerVelocity =
00131 velocities_.back();
00132 if(newerVelocity.first >= stampedTwist->header.stamp.toSec())
00133 {
00134 ROS_WARN_THROTTLE
00135 (5, "camera velocity estimation timestamp is inconsistent");
00136 return;
00137 }
00138 }
00139 if(!header_.frame_id.empty()
00140 && stampedTwist->header.frame_id != header_.frame_id)
00141 {
00142 ROS_WARN_THROTTLE
00143 (5, "velocity is not given in the wanted frame");
00144 return;
00145 }
00146
00147 vpColVector velocity(6);
00148 velocity[0] = stampedTwist->twist.linear.x;
00149 velocity[1] = stampedTwist->twist.linear.y;
00150 velocity[2] = stampedTwist->twist.linear.z;
00151 velocity[3] = stampedTwist->twist.angular.x;
00152 velocity[4] = stampedTwist->twist.angular.y;
00153 velocity[5] = stampedTwist->twist.angular.z;
00154
00155 velocities_.push_back(std::make_pair
00156 (stampedTwist->header.stamp.toSec(),
00157 velocity));
00158 }
00159
00160 void
00161 Tracker::updateMovingEdgeSites()
00162 {
00163 sites_.moving_edge_sites.clear();
00164
00165 std::list<vpMbtDistanceLine*> linesList;
00166 tracker_.getLline(linesList, 0);
00167
00168 std::list<vpMbtDistanceLine*>::iterator linesIterator =
00169 linesList.begin();
00170 for (; linesIterator != linesList.end(); ++linesIterator)
00171 {
00172 vpMbtDistanceLine* line = *linesIterator;
00173
00174 if (line && line->isVisible() && line->meline)
00175 {
00176 std::list<vpMeSite>::const_iterator sitesIterator =
00177 line->meline->list.begin();
00178 for (; sitesIterator != line->meline->list.end(); ++sitesIterator)
00179 {
00180 visp_tracker::MovingEdgeSite movingEdgeSite;
00181 movingEdgeSite.x = sitesIterator->ifloat;
00182 movingEdgeSite.y = sitesIterator->jfloat;
00183 movingEdgeSite.suppress = sitesIterator->suppress;
00184 }
00185 }
00186 }
00187 }
00188
00189 void Tracker::checkInputs()
00190 {
00191 ros::V_string topics;
00192 topics.push_back(rectifiedImageTopic_);
00193 checkInputs_.start(topics, 60.0);
00194 }
00195
00196 Tracker::Tracker(unsigned queueSize)
00197 : queueSize_(queueSize),
00198 nodeHandle_(),
00199 imageTransport_(nodeHandle_),
00200 state_(WAITING_FOR_INITIALIZATION),
00201 image_(),
00202 cameraPrefix_(),
00203 rectifiedImageTopic_(),
00204 cameraInfoTopic_(),
00205 vrmlPath_(),
00206 cameraSubscriber_(),
00207 reconfigureSrv_(),
00208 resultPublisher_(),
00209 transformationPublisher_(),
00210 movingEdgeSitesPublisher_(),
00211 cameraVelocitySubscriber_(),
00212 initService_(),
00213 header_(),
00214 info_(),
00215 movingEdge_(),
00216 cameraParameters_(),
00217 tracker_(),
00218 sites_(),
00219 lastTrackedImage_(),
00220 checkInputs_(ros::NodeHandle(), ros::this_node::getName()),
00221 cMo_ (),
00222 velocities_ (MAX_VELOCITY_VALUES),
00223 transformBroadcaster_ (),
00224 childFrameId_ ()
00225 {
00226
00227 cMo_.eye();
00228
00229
00230 ros::param::param<std::string>("~camera_prefix", cameraPrefix_, "");
00231
00232 if (cameraPrefix_.empty ())
00233 {
00234 ROS_FATAL
00235 ("The camera_prefix parameter not set.\n"
00236 "Please relaunch the tracker while setting this parameter, i.e.\n"
00237 "$ rosrun visp_tracker tracker _camera_prefix:=/my/camera");
00238 ros::shutdown ();
00239 return;
00240 }
00241 ros::param::set("camera_prefix", cameraPrefix_);
00242
00243 ros::param::param<std::string>("frame_id", childFrameId_, "object_position");
00244
00245
00246 rectifiedImageTopic_ =
00247 ros::names::resolve(cameraPrefix_ + "/image_rect");
00248
00249
00250 checkInputs();
00251
00252
00253 resultPublisher_ =
00254 nodeHandle_.advertise<visp_tracker::TrackingResult>
00255 (visp_tracker::result_topic, queueSize_);
00256
00257 transformationPublisher_ =
00258 nodeHandle_.advertise<geometry_msgs::TransformStamped>
00259 (visp_tracker::object_position_topic, queueSize_);
00260
00261
00262 movingEdgeSitesPublisher_ =
00263 nodeHandle_.advertise<visp_tracker::MovingEdgeSites>
00264 (visp_tracker::moving_edge_sites_topic, queueSize_);
00265
00266
00267 typedef boost::function<
00268 void (const geometry_msgs::TwistStampedConstPtr&)>
00269 cameraVelocitycallback_t;
00270 cameraVelocitycallback_t callback =
00271 boost::bind(&Tracker::cameraVelocityCallback, this, _1);
00272 cameraVelocitySubscriber_ =
00273 nodeHandle_.subscribe(camera_velocity_topic, queueSize_, callback);
00274
00275
00276 cameraSubscriber_ =
00277 imageTransport_.subscribeCamera
00278 (rectifiedImageTopic_, queueSize_,
00279 bindImageCallback(image_, header_, info_));
00280
00281
00282 movingEdge_.initMask();
00283 tracker_.setMovingEdge(movingEdge_);
00284
00285
00286 reconfigureSrv_t::CallbackType f =
00287 boost::bind(&reconfigureCallback, boost::ref(tracker_),
00288 boost::ref(image_), boost::ref(movingEdge_), _1, _2);
00289 reconfigureSrv_.setCallback(f);
00290
00291
00292 waitForImage();
00293 if (!ros::ok())
00294 return;
00295 if (!image_.getWidth() || !image_.getHeight())
00296 throw std::runtime_error("failed to retrieve image");
00297
00298
00299 initializeVpCameraFromCameraInfo(cameraParameters_, info_);
00300 tracker_.setCameraParameters(cameraParameters_);
00301 tracker_.setDisplayMovingEdges(false);
00302
00303 ROS_INFO_STREAM(cameraParameters_);
00304
00305
00306 initCallback_t initCallback =
00307 boost::bind(&Tracker::initCallback, this, _1, _2);
00308
00309 initService_ = nodeHandle_.advertiseService
00310 (visp_tracker::init_service, initCallback);
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 void Tracker::integrateCameraVelocity(const std_msgs::Header& lastHeader,
00349 const std_msgs::Header& currentHeader)
00350 {
00351
00352 if (currentHeader.stamp <= lastHeader.stamp)
00353 {
00354 ROS_DEBUG_THROTTLE(5, "new image is older than previous one");
00355 return;
00356 }
00357
00358
00359 if (velocities_.empty())
00360 return;
00361
00362
00363 double start = lastHeader.stamp.toSec();
00364 double end = currentHeader.stamp.toSec();
00365
00366
00367
00368 velocities_t::iterator it = velocities_.begin();
00369 for(; it != velocities_.end() && it->first < start; ++it)
00370 ;
00371
00372
00373
00374
00375
00376
00377 if (it != velocities_.begin())
00378 {
00379 --it;
00380 velocities_.erase(velocities_.begin(), it);
00381 }
00382
00383
00384 if (velocities_.empty())
00385 return;
00386
00387
00388
00389 it = velocities_.begin();
00390
00391 vpHomogeneousMatrix cMc_;
00392 cMc_.eye();
00393
00394 for(; it != velocities_.end(); ++it)
00395 {
00396 velocities_t::iterator current = it;
00397 velocities_t::iterator next = it; ++next;
00398
00399
00400
00401 if (current->first >= end)
00402 break;
00403
00404
00405 double s = std::max(start, current->first);
00406 double e = 0.;
00407
00408 if (next == velocities_.end())
00409 e = end;
00410 else
00411 e = std::min(end, next->first);
00412 double dt = e - s;
00413 const vpColVector& velocity = it->second;
00414
00415 if (dt < 0.)
00416 ROS_DEBUG_THROTTLE(5, "invalid dt");
00417 if (velocity.getRows() != 6)
00418 throw std::runtime_error
00419 ("invalid colum size during velocity integration");
00420
00421
00422 cMc_ = vpExponentialMap::direct(velocity, dt) * cMc_;
00423 }
00424
00425 if (it != velocities_.begin())
00426 {
00427 --it;
00428 velocities_.erase(velocities_.begin(), it);
00429 }
00430
00431 ROS_DEBUG_STREAM_THROTTLE
00432 (5,
00433 "applying control feedback, camera motion estimation is:\n" << cMc_);
00434 cMo_ = cMc_.inverse() * cMo_;
00435 }
00436
00437 std::string
00438 Tracker::velocitiesDebugMessage()
00439 {
00440 std::stringstream ss;
00441 ss << "velocities_ array size: " << velocities_.size() << "\n";
00442 if (!velocities_.empty())
00443 ss << "Velocities:\n";
00444 for (unsigned i = 0;
00445 i < std::min(velocities_.size(), static_cast<std::size_t> (10u)); ++i)
00446 ss << "- t = " << velocities_[i].first
00447 << " / v(t) = \n" << velocities_[i].second << "\n";
00448 return ss.str();
00449 }
00450
00451 void Tracker::spin()
00452 {
00453 ros::Rate loopRateTracking(100);
00454 visp_tracker::TrackingResult result;
00455 geometry_msgs::TransformStamped objectPosition;
00456 tf::Transform transform;
00457 std_msgs::Header lastHeader;
00458
00459 while (ros::ok())
00460 {
00461
00462
00463
00464 if (header_.seq < lastHeader.seq)
00465 lastTrackedImage_ = 0;
00466
00467 if (lastTrackedImage_ < header_.seq)
00468 {
00469 lastTrackedImage_ = header_.seq;
00470
00471
00472 try
00473 {
00474 integrateCameraVelocity(lastHeader, header_);
00475 }
00476 catch(std::exception& e)
00477 {
00478 ROS_WARN_STREAM_THROTTLE(5, e.what());
00479 }
00480
00481 if (state_ == TRACKING || state_ == LOST)
00482 try
00483 {
00484 tracker_.init(image_, cMo_);
00485 tracker_.track(image_);
00486 tracker_.getPose(cMo_);
00487 }
00488 catch(...)
00489 {
00490 ROS_WARN_THROTTLE(10, "tracking lost");
00491 state_ = LOST;
00492 }
00493
00494
00495 if (state_ == TRACKING)
00496 {
00497
00498 objectPosition.header = header_;
00499 objectPosition.child_frame_id = childFrameId_;
00500 vpHomogeneousMatrixToTransform(objectPosition.transform, cMo_);
00501 transformationPublisher_.publish(objectPosition);
00502
00503
00504 result.header = header_;
00505 result.is_tracking = true;
00506 result.cMo = objectPosition.transform;
00507 resultPublisher_.publish(result);
00508
00509
00510 updateMovingEdgeSites();
00511 sites_.header = header_;
00512 movingEdgeSitesPublisher_.publish(sites_);
00513
00514
00515 transform.setOrigin
00516 (tf::Vector3(objectPosition.transform.translation.x,
00517 objectPosition.transform.translation.y,
00518 objectPosition.transform.translation.z));
00519 transform.setRotation
00520 (tf::Quaternion
00521 (objectPosition.transform.rotation.x,
00522 objectPosition.transform.rotation.y,
00523 objectPosition.transform.rotation.z,
00524 objectPosition.transform.rotation.w));
00525 transformBroadcaster_.sendTransform
00526 (tf::StampedTransform
00527 (transform,
00528 objectPosition.header.stamp,
00529 objectPosition.header.frame_id,
00530 childFrameId_));
00531 }
00532 else
00533 {
00534 result.header = header_;
00535 result.is_tracking = false;
00536 result.cMo.translation.x = 0.;
00537 result.cMo.translation.y = 0.;
00538 result.cMo.translation.z = 0.;
00539
00540 result.cMo.rotation.x = 0.;
00541 result.cMo.rotation.y = 0.;
00542 result.cMo.rotation.z = 0.;
00543 result.cMo.rotation.w = 0.;
00544
00545 sites_.moving_edge_sites.clear();
00546 }
00547 }
00548 lastHeader = header_;
00549
00550 ROS_DEBUG_STREAM_THROTTLE (5, velocitiesDebugMessage());
00551
00552 ros::spinOnce();
00553 loopRateTracking.sleep();
00554 }
00555 }
00556
00557 void
00558 Tracker::waitForImage()
00559 {
00560 ros::Rate loop_rate(10);
00561 while (ros::ok()
00562 && (!image_.getWidth() || !image_.getHeight()))
00563 {
00564 ROS_INFO_THROTTLE(1, "waiting for a rectified image...");
00565 ros::spinOnce();
00566 loop_rate.sleep();
00567 }
00568 }
00569
00570 }