45 #include <geometry_msgs/Pose.h>    46 #include <geometry_msgs/PoseArray.h>    47 #include <geometry_msgs/Twist.h>    53 #include <visp3/core/vpConfig.h>    54 #include <visp3/core/vpExponentialMap.h>    55 #include <visp3/core/vpImageConvert.h>    56 #include <visp3/core/vpMomentAreaNormalized.h>    57 #include <visp3/core/vpMomentBasic.h>    58 #include <visp3/core/vpMomentCentered.h>    59 #include <visp3/core/vpMomentDatabase.h>    60 #include <visp3/core/vpMomentGravityCenter.h>    61 #include <visp3/core/vpMomentGravityCenterNormalized.h>    62 #include <visp3/core/vpMomentObject.h>    63 #include <visp3/core/vpPixelMeterConversion.h>    64 #include <visp3/core/vpPoint.h>    65 #include <visp3/core/vpTime.h>    66 #include <visp3/detection/vpDetectorAprilTag.h>    67 #include <visp3/gui/vpDisplayX.h>    68 #include <visp3/visual_features/vpFeatureBuilder.h>    69 #include <visp3/visual_features/vpFeatureMomentAreaNormalized.h>    70 #include <visp3/visual_features/vpFeatureMomentGravityCenterNormalized.h>    71 #include <visp3/visual_features/vpFeatureVanishingPoint.h>    72 #include <visp3/vs/vpServo.h>    73 #include <visp3/vs/vpServoDisplay.h>    78 #if VISP_VERSION_INT > VP_VERSION_INT( 3, 2, 0 ) // ViSP >= 3.0.0    92     ROS_WARN( 
"No tag size parameter has been found, using default value : 0.14 meters." );
   101   if ( nh.
hasParam( 
"/vs/distanceToTag" ) )
   103     nh.
getParam( 
"/vs/distanceToTag", res );
   108     ROS_WARN( 
"No distance to tag parameter has been found, using default value : 1.5 meters." );
   114 compareImagePoint( std::pair< size_t, vpImagePoint > p1, std::pair< size_t, vpImagePoint > p2 )
   116   return ( p1.second.get_v() < p2.second.get_v() );
   123   virtual ~bebopVSNodelet();
   135   bool bebop_has_been_setup;
   137   vpDisplayX m_display;
   138   bool m_display_setup;
   139   vpImage< unsigned char > I;
   148   vpDetectorAprilTag m_detector;
   149   vpCameraParameters m_cam;
   151   bool m_vec_ip_has_been_sorted;
   152   std::vector< std::pair< size_t, vpImagePoint > > m_vec_ip_sorted;
   154   vpVelocityTwistMatrix m_cVe;
   164   vpMomentObject m_obj, m_obj_d;
   165   vpMomentDatabase mdb, mdb_d;
   167   vpMomentGravityCenter mg, mg_d;
   168   vpMomentCentered mc, mc_d;
   169   vpMomentAreaNormalized man, man_d;
   170   vpMomentGravityCenterNormalized mgn, mgn_d;
   172   vpFeatureMomentGravityCenterNormalized s_mgn, s_mgn_d;
   173   vpFeatureMomentAreaNormalized s_man, s_man_d;
   174   vpFeatureVanishingPoint s_vp, s_vp_d;
   177   vpColVector velocityToPosition( vpColVector &vel_cmd, 
double delta_t );
   182 bebopVSNodelet::bebopVSNodelet()
   183   : bebop_has_been_setup( false )
   184   , m_display_setup( false )
   185   , m_tagSize( getTagSize( m_nh ) )   
   186   , m_Z_d( getDistanceToTag( m_nh ) ) 
   187   , m_cameraTilt( 0.0 )
   189   , m_detector( vpDetectorAprilTag::TAG_36h11 )
   190   , m_vec_ip_has_been_sorted( false )
   191   , m_eJe( vpMatrix( 6, 4, 0 ) )
   200   , s_mgn( mdb, 
A, B, C )
   201   , s_mgn_d( mdb_d, 
A, B, C )
   202   , s_man( mdb, 
A, B, C )
   203   , s_man_d( mdb_d, 
A, B, C )
   207 bebopVSNodelet::~bebopVSNodelet() { m_task.kill(); }
   210 bebopVSNodelet::onInit()
   213   m_nh = getNodeHandle();
   214   std::stringstream params_str;
   215   params_str << 
"TAG PARAMETERS (meters) : tagSize : " << m_tagSize << 
" - distanceToTag : " << m_Z_d << std::endl;
   220   NODELET_INFO( 
"Setting up publisher and subscriber..." );
   221   m_pubTwist = m_nh.advertise< geometry_msgs::Twist >( 
"cmd_moveby", 1000 );
   222   m_subImg   = m_nh.subscribe( 
"image_raw", 1000, &bebopVSNodelet::imageCallback, 
this );
   223   m_pubCam   = m_nh.advertise< geometry_msgs::Twist >( 
"camera_control", 1000 );
   224   NODELET_INFO( 
"Publisher and subscriber set up. Waiting for image callbacks..." );
   228 bebopVSNodelet::imageCallback( 
const sensor_msgs::ImageConstPtr &msg )
   230   if ( !bebop_has_been_setup )
   232     geometry_msgs::Twist out_cam_ctrl;
   233     out_cam_ctrl.linear.x  = 0;
   234     out_cam_ctrl.linear.y  = 0;
   235     out_cam_ctrl.linear.z  = 0;
   236     out_cam_ctrl.angular.x = 0;
   237     out_cam_ctrl.angular.y = m_cameraTilt;
   238     out_cam_ctrl.angular.z = m_cameraPan;
   239     m_pubCam.publish( out_cam_ctrl );
   241     bebop_has_been_setup = 
true;
   242     NODELET_INFO( 
"Setting desired camera orientation..." );
   246   vpImageConvert::convert( frame, I );
   248   if ( !m_display_setup )
   250     m_display.init( I, 100, 100, 
"DRONE VIEW" );
   251     m_display_setup = 
true;
   253   vpDisplay::display( I );
   255   std::vector< vpHomogeneousMatrix > cMo_vec;
   256   m_detector.detect( I, m_tagSize, m_cam, cMo_vec ); 
   258   geometry_msgs::Twist out_cmd_pos;
   260   if ( m_detector.getNbObjects() == 1 )
   263     std::vector< vpImagePoint > vec_ip = m_detector.getPolygon( 0 );
   264     std::vector< vpPoint > vec_P;
   265     for ( 
size_t i = 0; i < vec_ip.size(); i++ )
   268       vpPixelMeterConversion::convertPoint( m_cam, vec_ip[i], x, y );
   272       vec_P.push_back( P );
   276     m_obj.setType( vpMomentObject::DENSE_POLYGON ); 
   277     m_obj.fromVector( vec_P );                      
   283     mdb.updateAll( m_obj );     
   286     man.setDesiredArea( area ); 
   290     s_mgn.update( 
A, B, C );
   291     s_mgn.compute_interaction();
   292     s_man.update( 
A, B, C );
   293     s_man.compute_interaction();
   298     if ( !m_vec_ip_has_been_sorted )
   300       for ( 
size_t i = 0; i < vec_ip.size(); i++ )
   303         std::pair< size_t, vpImagePoint > index_pair = std::pair< size_t, vpImagePoint >( i, vec_ip[i] );
   304         m_vec_ip_sorted.push_back( index_pair );
   308       std::sort( m_vec_ip_sorted.begin(), m_vec_ip_sorted.end(), compareImagePoint );
   310       m_vec_ip_has_been_sorted = 
true;
   314     vpFeatureBuilder::create( s_vp, m_cam, vec_ip[m_vec_ip_sorted[0].first], vec_ip[m_vec_ip_sorted[1].first],
   315                               vec_ip[m_vec_ip_sorted[2].first], vec_ip[m_vec_ip_sorted[3].first],
   316                               vpFeatureVanishingPoint::selectAtanOneOverRho() );
   318     m_task.set_cVe( m_cVe );
   319     m_task.set_eJe( m_eJe );
   322     vpColVector ve = m_task.computeControlLaw();
   323     std::stringstream ve_str;
   324     ve_str << 
"ve: " << ve.t() << std::endl;
   328     vpColVector cmd_pos = velocityToPosition( ve, 1.0 );
   332     out_cmd_pos.linear.x  = cmd_pos[0];
   333     out_cmd_pos.linear.y  = cmd_pos[1];
   334     out_cmd_pos.linear.z  = cmd_pos[2];
   335     out_cmd_pos.angular.x = 0;
   336     out_cmd_pos.angular.y = 0;
   337     out_cmd_pos.angular.z = cmd_pos[3];
   338     m_pubTwist.publish( out_cmd_pos );
   340     for ( 
size_t i = 0; i < 4; i++ )
   342       vpDisplay::displayCross( I, vec_ip[i], 15, vpColor::red, 1 );
   343       std::stringstream ss;
   345       vpDisplay::displayText( I, vec_ip[i] + vpImagePoint( 15, 15 ), ss.str(), vpColor::green );
   349     vpDisplay::displayPolygon( I, vec_ip, vpColor::green,
   351     vpDisplay::displayCross( I, m_detector.getCog( 0 ), 15, vpColor::green,
   353     vpDisplay::displayLine( I, 0, static_cast< int >( m_cam.get_u0() ), static_cast< int >( I.getHeight() ) - 1,
   354                             static_cast< int >( m_cam.get_u0() ), vpColor::red,
   356     vpDisplay::displayLine( I, static_cast< int >( m_cam.get_v0() ), 0, static_cast< int >( m_cam.get_v0() ),
   357                             static_cast< int >( I.getWidth() ) - 1, vpColor::red,
   361     vpDisplay::displayLine( I, vec_ip[m_vec_ip_sorted[0].first], vec_ip[m_vec_ip_sorted[1].first], vpColor::red, 1,
   363     vpDisplay::displayLine( I, vec_ip[m_vec_ip_sorted[2].first], vec_ip[m_vec_ip_sorted[3].first], vpColor::red, 1,
   366     vpDisplay::displayText( I, 10, 10, 
"Click to exit", vpColor::red );
   367     vpDisplay::flush( I );
   372     std::stringstream sserr;
   373     sserr << 
"Failed to detect an Apriltag, or detected multiple ones";
   374     vpDisplay::displayText( I, 120, 20, sserr.str(), vpColor::red );
   375     vpDisplay::flush( I );
   378     out_cmd_pos.linear.x  = 0;
   379     out_cmd_pos.linear.y  = 0;
   380     out_cmd_pos.linear.z  = 0;
   381     out_cmd_pos.angular.x = 0;
   382     out_cmd_pos.angular.y = 0;
   383     out_cmd_pos.angular.z = 0;
   384     m_pubTwist.publish( out_cmd_pos );
   389 bebopVSNodelet::initVS()
   393   m_detector.setAprilTagQuadDecimate( 4.0 );
   394   m_detector.setAprilTagNbThreads( 4 );
   395   m_detector.setDisplayTag( 
true );
   397   m_cam.initPersProjWithoutDistortion( 531.9213063, 520.8495788, 429.133986, 240.9464457 );
   398   m_cam.printParameters();
   401   vpAdaptiveGain lambda = vpAdaptiveGain( 1.5, 0.7, 30 );
   402   m_task.setServo( vpServo::EYEINHAND_L_cVe_eJe );
   403   m_task.setInteractionMatrixType( vpServo::CURRENT );
   404   m_task.setLambda( lambda );
   406   if ( m_nh.hasParam( 
"/vs/cameraTilt" ) )
   408     m_nh.getParam( 
"/vs/cameraTilt", m_cameraTilt );
   412     ROS_WARN( 
"No camera tilt value found, using default value : -15 degrees." );
   413     m_cameraTilt = -15.0;
   416   if ( m_nh.hasParam( 
"/vs/cameraPan" ) )
   418     m_nh.getParam( 
"/vs/cameraPan", m_cameraPan );
   422     ROS_WARN( 
"No camera pan value found, using default value : 0 degrees." );
   426   std::stringstream camparams_str;
   427   camparams_str << 
"CAMERA PARAMETERS (degrees) : camera Tilt : " << m_cameraTilt << 
" - camera pan : " << m_cameraPan
   431   vpRxyzVector c1_rxyz_c2( vpMath::rad( m_cameraTilt ), vpMath::rad( m_cameraPan ), 0 );
   433   vpRotationMatrix c1Rc2( c1_rxyz_c2 );                      
   434   vpHomogeneousMatrix c1Mc2( vpTranslationVector(), c1Rc2 ); 
   436   vpRotationMatrix c1Re{ 0, 1, 0, 0, 0, 1, 1, 0, 0 }; 
   437   vpTranslationVector c1te( 0, 0, -0.09 );            
   438   vpHomogeneousMatrix c1Me( c1te, c1Re );             
   440   vpHomogeneousMatrix c2Me = c1Mc2.inverse() * c1Me; 
   443   m_cVe = vpVelocityTwistMatrix( c2Me );
   444   m_task.set_cVe( m_cVe );
   452   double X[4] = { m_tagSize / 2., m_tagSize / 2., -m_tagSize / 2., -m_tagSize / 2. };
   453   double Y[4] = { m_tagSize / 2., -m_tagSize / 2., -m_tagSize / 2., m_tagSize / 2. };
   455   std::vector< vpPoint > vec_P, vec_P_d;
   456   for ( 
int i = 0; i < 4; i++ )
   458     vpPoint P_d( X[i], Y[i], 0 );
   459     vpHomogeneousMatrix cdMo( 0, 0, m_Z_d, 0, 0, 0 );
   461     vec_P_d.push_back( P_d );
   465   m_obj_d.setType( vpMomentObject::DENSE_POLYGON ); 
   466   m_obj_d.fromVector( vec_P_d );                    
   468   mb_d.linkTo( mdb_d );       
   469   mg_d.linkTo( mdb_d );       
   470   mc_d.linkTo( mdb_d );       
   471   man_d.linkTo( mdb_d );      
   472   mgn_d.linkTo( mdb_d );      
   473   mdb_d.updateAll( m_obj_d ); 
   477   if ( m_obj_d.getType() == vpMomentObject::DISCRETE )
   478     area = mb_d.get( 2, 0 ) + mb_d.get( 0, 2 );
   480     area = mb_d.get( 0, 0 );
   482   man_d.setDesiredArea( area );
   488   m_task.addFeature( s_mgn, s_mgn_d );
   489   m_task.addFeature( s_man, s_man_d );
   490   m_task.addFeature( s_vp, s_vp_d, vpFeatureVanishingPoint::selectAtanOneOverRho() );
   493   s_mgn_d.update( 
A, B, C );
   494   s_mgn_d.compute_interaction();
   496   s_man_d.update( 
A, B, C );
   497   s_man_d.compute_interaction();
   500   s_vp_d.setAtanOneOverRho( 0 );
   501   s_vp_d.setAlpha( 0 );
   507 bebopVSNodelet::velocityToPosition( vpColVector &vel_cmd, 
double delta_t )
   510   if ( vel_cmd.size() != 4 )
   512     ROS_ERROR( 
"Can't compute velocity : dimension of the velocity vector should be equal to 4." );
   513     res << 0., 0., 0., 0.;
   524   vpHomogeneousMatrix M = vpExponentialMap::direct( ve, delta_t );
   526   double epsilon = ( std::numeric_limits< double >::epsilon() );
   527   if ( std::abs( M.getRotationMatrix().getThetaUVector()[0] ) >= epsilon )
   529     ROS_ERROR( 
"Can't compute velocity : rotation around X axis should be 0." );
   530     res << 0., 0., 0., 0.;
   533   if ( std::abs( M.getRotationMatrix().getThetaUVector()[1] ) >= epsilon )
   535     ROS_ERROR( 
"Can't compute velocity : rotation around Y axis should be 0." );
   536     res << 0., 0., 0., 0.;
   540   float dThetaZ         = 
static_cast< float >( M.getRotationMatrix().getThetaUVector()[2] );
   541   vpTranslationVector t = M.getTranslationVector();
   543   res << t[0], t[1], t[2], dThetaZ;
 CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
void imageCallback(const sensor_msgs::ImageConstPtr &msg)
bool getParam(const std::string &key, std::string &s) const
bool hasParam(const std::string &key) const
#define NODELET_INFO(...)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)