37 #include <visp3/core/vpCameraParameters.h>
38 #include <visp3/detection/vpDetectorAprilTag.h>
39 #include <visp3/gui/vpDisplayOpenCV.h>
40 #include <visp3/gui/vpPlot.h>
41 #include <visp3/io/vpImageIo.h>
42 #include <visp3/visual_features/vpFeatureThetaU.h>
43 #include <visp3/visual_features/vpFeatureTranslation.h>
44 #include <visp3/vs/vpServo.h>
45 #include <visp3/vs/vpServoDisplay.h>
52 std::vector< vpImagePoint > *traj_vip )
54 for (
size_t i = 0; i < vip.size(); i++ )
56 if ( traj_vip[i].size() )
59 if ( vpImagePoint::distance( vip[i], traj_vip[i].back() ) > 1. )
61 traj_vip[i].push_back( vip[i] );
66 traj_vip[i].push_back( vip[i] );
69 for (
size_t i = 0; i < vip.size(); i++ )
71 for (
size_t j = 1; j < traj_vip[i].size(); j++ )
73 vpDisplay::displayLine( I, traj_vip[i][j - 1], traj_vip[i][j], vpColor::green, 2 );
79 main(
int argc,
char **argv )
81 double opt_tagSize = 0.08;
82 bool display_tag =
true;
83 int opt_quad_decimate = 2;
84 bool opt_verbose =
false;
85 bool opt_plot =
false;
86 bool opt_adaptive_gain =
false;
87 bool opt_task_sequencing =
false;
88 double convergence_threshold_t = 0.0005, convergence_threshold_tu = vpMath::rad( 0.5 );
89 bool opt_coppeliasim_sync_mode =
false;
91 for (
int i = 1; i < argc; i++ )
93 if ( std::string( argv[i] ) ==
"--tag_size" && i + 1 < argc )
95 opt_tagSize = std::stod( argv[i + 1] );
97 else if ( std::string( argv[i] ) ==
"--verbose" || std::string( argv[i] ) ==
"-v" )
101 else if ( std::string( argv[i] ) ==
"--plot" )
105 else if ( std::string( argv[i] ) ==
"--adaptive_gain" )
107 opt_adaptive_gain =
true;
109 else if ( std::string( argv[i] ) ==
"--task_sequencing" )
111 opt_task_sequencing =
true;
113 else if ( std::string( argv[i] ) ==
"--quad_decimate" && i + 1 < argc )
115 opt_quad_decimate = std::stoi( argv[i + 1] );
117 else if ( std::string( argv[i] ) ==
"--no-convergence-threshold" )
119 convergence_threshold_t = 0.;
120 convergence_threshold_tu = 0.;
122 else if ( std::string( argv[i] ) ==
"--enable-coppeliasim-sync-mode" )
124 opt_coppeliasim_sync_mode =
true;
126 else if ( std::string( argv[i] ) ==
"--help" || std::string( argv[i] ) ==
"-h" )
128 std::cout << argv[0] <<
"[--tag_size <marker size in meter; default " << opt_tagSize <<
">] "
129 <<
"[--quad_decimate <decimation; default " << opt_quad_decimate <<
">] "
130 <<
"[--adaptive_gain] "
132 <<
"[--task_sequencing] "
133 <<
"[--no-convergence-threshold] "
134 <<
"[--enable-coppeliasim-sync-mode] "
135 <<
"[--verbose] [-v] "
136 <<
"[--help] [-h]" << std::endl;
155 std::cout <<
"Coppeliasim sync mode enabled: " << ( opt_coppeliasim_sync_mode ?
"yes" :
"no" ) << std::endl;
165 std::cout <<
"Initial joint position: " << q.t() << std::endl;
167 q[0] += vpMath::rad( 10 );
168 std::cout <<
"Move to joint position: " << q.t() << std::endl;
172 vpImage< unsigned char > I;
176 g.
open( argc, argv );
180 std::cout <<
"Image size: " << I.getWidth() <<
" x " << I.getHeight() << std::endl;
181 vpCameraParameters cam;
184 std::cout << cam << std::endl;
185 vpDisplayOpenCV dc( I, 10, 10,
"Color image" );
187 vpDetectorAprilTag::vpAprilTagFamily tagFamily = vpDetectorAprilTag::TAG_36h11;
188 vpDetectorAprilTag::vpPoseEstimationMethod poseEstimationMethod = vpDetectorAprilTag::HOMOGRAPHY_VIRTUAL_VS;
189 vpDetectorAprilTag detector( tagFamily );
190 detector.setAprilTagPoseEstimationMethod( poseEstimationMethod );
191 detector.setDisplayTag( display_tag );
192 detector.setAprilTagQuadDecimate( opt_quad_decimate );
195 vpHomogeneousMatrix cdMc, cMo, oMo;
198 vpHomogeneousMatrix cdMo( vpTranslationVector( 0, 0.0, opt_tagSize * 3 ),
199 vpRotationMatrix( { 1, 0, 0, 0, -1, 0, 0, 0, -1 } ) );
200 cdMc = cdMo * cMo.inverse();
203 vpFeatureTranslation t( vpFeatureTranslation::cdMc );
204 vpFeatureThetaU tu( vpFeatureThetaU::cdRc );
206 tu.buildFrom( cdMc );
208 vpFeatureTranslation td( vpFeatureTranslation::cdMc );
209 vpFeatureThetaU tud( vpFeatureThetaU::cdRc );
213 task.addFeature( t, td );
214 task.addFeature( tu, tud );
216 task.setServo( vpServo::EYEINHAND_CAMERA );
217 task.setInteractionMatrixType( vpServo::CURRENT );
219 if ( opt_adaptive_gain )
221 std::cout <<
"Enable adaptive gain" << std::endl;
222 vpAdaptiveGain lambda( 4, 1.2, 25 );
223 task.setLambda( lambda );
227 task.setLambda( 1.2 );
230 vpPlot *plotter =
nullptr;
234 plotter =
new vpPlot( 2,
static_cast< int >( 250 * 2 ), 500,
static_cast< int >( I.getWidth() ) + 80, 10,
235 "Real time curves plotter" );
236 plotter->setTitle( 0,
"Visual features error" );
237 plotter->setTitle( 1,
"Camera velocities" );
238 plotter->initGraph( 0, 6 );
239 plotter->initGraph( 1, 6 );
240 plotter->setLegend( 0, 0,
"error_feat_tx" );
241 plotter->setLegend( 0, 1,
"error_feat_ty" );
242 plotter->setLegend( 0, 2,
"error_feat_tz" );
243 plotter->setLegend( 0, 3,
"error_feat_theta_ux" );
244 plotter->setLegend( 0, 4,
"error_feat_theta_uy" );
245 plotter->setLegend( 0, 5,
"error_feat_theta_uz" );
246 plotter->setLegend( 1, 0,
"vc_x" );
247 plotter->setLegend( 1, 1,
"vc_y" );
248 plotter->setLegend( 1, 2,
"vc_z" );
249 plotter->setLegend( 1, 3,
"wc_x" );
250 plotter->setLegend( 1, 4,
"wc_y" );
251 plotter->setLegend( 1, 5,
"wc_z" );
254 bool final_quit =
false;
255 bool has_converged =
false;
256 bool send_velocities =
false;
257 bool servo_started =
false;
258 std::vector< vpImagePoint > *traj_corners =
nullptr;
261 double sim_time_prev = sim_time;
262 double sim_time_init_servo = sim_time;
263 double sim_time_img = sim_time;
268 vpHomogeneousMatrix eMc;
269 eMc.buildFrom( 0.05, -0.05, 0, 0, 0, M_PI_4 );
272 std::cout <<
"eMc:\n" << robot.
get_eMc() << std::endl;
277 while ( !final_quit )
282 vpDisplay::display( I );
284 std::vector< vpHomogeneousMatrix > cMo_vec;
285 detector.detect( I, opt_tagSize, cam, cMo_vec );
288 std::stringstream ss;
289 ss <<
"Left click to " << ( send_velocities ?
"stop the robot" :
"servo the robot" )
290 <<
", right click to quit.";
291 vpDisplay::displayText( I, 20, 20, ss.str(), vpColor::red );
294 vpColVector v_c( 6 );
297 if ( cMo_vec.size() == 1 )
301 static bool first_time =
true;
305 std::vector< vpHomogeneousMatrix > v_oMo( 2 ), v_cdMc( 2 );
306 v_oMo[1].buildFrom( 0, 0, 0, 0, 0, M_PI );
307 for (
size_t i = 0; i < 2; i++ )
309 v_cdMc[i] = cdMo * v_oMo[i] * cMo.inverse();
311 if ( std::fabs( v_cdMc[0].getThetaUVector().getTheta() ) <
312 std::fabs( v_cdMc[1].getThetaUVector().getTheta() ) )
318 std::cout <<
"Desired frame modified to avoid PI rotation of the camera" << std::endl;
324 cdMc = cdMo * oMo * cMo.inverse();
326 tu.buildFrom( cdMc );
328 if ( opt_task_sequencing )
330 if ( !servo_started )
332 if ( send_velocities )
334 servo_started =
true;
342 v_c = task.computeControlLaw();
347 vpDisplay::displayFrame( I, cdMo * oMo, cam, opt_tagSize / 1.5, vpColor::yellow, 2 );
348 vpDisplay::displayFrame( I, cMo, cam, opt_tagSize / 2, vpColor::none, 3 );
351 std::vector< vpImagePoint > corners = detector.getPolygon( 0 );
354 corners.push_back( detector.getCog( 0 ) );
358 traj_corners =
new std::vector< vpImagePoint >[corners.size()];
366 plotter->plot( 0,
static_cast< double >( sim_time ), task.getError() );
367 plotter->plot( 1,
static_cast< double >( sim_time ), v_c );
372 std::cout <<
"v_c: " << v_c.t() << std::endl;
375 vpTranslationVector cd_t_c = cdMc.getTranslationVector();
376 vpThetaUVector cd_tu_c = cdMc.getThetaUVector();
377 double error_tr = sqrt( cd_t_c.sumSquare() );
378 double error_tu = vpMath::deg( sqrt( cd_tu_c.sumSquare() ) );
380 std::stringstream ss;
381 ss <<
"error_t: " << error_tr;
382 vpDisplay::displayText( I, 20,
static_cast< int >( I.getWidth() ) - 150, ss.str(), vpColor::red );
384 ss <<
"error_tu: " << error_tu;
385 vpDisplay::displayText( I, 40,
static_cast< int >( I.getWidth() ) - 150, ss.str(), vpColor::red );
388 std::cout <<
"error translation: " << error_tr <<
" ; error rotation: " << error_tu << std::endl;
390 if ( !has_converged && error_tr < convergence_threshold_t && error_tu < convergence_threshold_tu )
392 has_converged =
true;
393 std::cout <<
"Servo task has converged"
395 vpDisplay::displayText( I, 100, 20,
"Servo task has converged", vpColor::red );
408 if ( !send_velocities )
415 std::stringstream ss;
416 ss <<
"Loop time [s]: " << std::round( ( sim_time - sim_time_prev ) * 1000. ) / 1000.;
417 ss <<
" Simulation time [s]: " << sim_time;
418 sim_time_prev = sim_time;
419 vpDisplay::displayText( I, 40, 20, ss.str(), vpColor::red );
421 vpMouseButton::vpMouseButtonType button;
422 if ( vpDisplay::getClick( I, button,
false ) )
426 case vpMouseButton::button1:
427 send_velocities = !send_velocities;
430 case vpMouseButton::button3:
440 vpDisplay::flush( I );
441 robot.
wait( sim_time, 0.020 );
444 if ( opt_plot && plotter !=
nullptr )
453 while ( !final_quit )
456 vpDisplay::display( I );
458 vpDisplay::displayText( I, 20, 20,
"Click to quit the program.", vpColor::red );
459 vpDisplay::displayText( I, 40, 20,
"Visual servo converged.", vpColor::red );
461 if ( vpDisplay::getClick( I,
false ) )
466 vpDisplay::flush( I );
471 delete[] traj_corners;
474 catch (
const vpException &e )
476 std::cout <<
"ViSP exception: " << e.what() << std::endl;
477 std::cout <<
"Stop the robot " << std::endl;