58 #include <visp3/core/vpCameraParameters.h>
59 #include <visp3/detection/vpDetectorAprilTag.h>
60 #include <visp3/gui/vpDisplayOpenCV.h>
61 #include <visp3/gui/vpPlot.h>
62 #include <visp3/io/vpImageIo.h>
63 #include <visp3/visual_features/vpFeatureThetaU.h>
64 #include <visp3/visual_features/vpFeatureTranslation.h>
65 #include <visp3/vs/vpServo.h>
66 #include <visp3/vs/vpServoDisplay.h>
68 #include <visp3/robot/vpRobotFranka.h>
69 #include <visp3/sensor/vpRealSense2.h>
71 #if defined( VISP_HAVE_REALSENSE2 ) && ( VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11 ) && \
72 ( defined( VISP_HAVE_OPENCV ) ) && defined( VISP_HAVE_FRANKA )
76 std::vector< vpImagePoint > *traj_vip )
78 for (
size_t i = 0; i < vip.size(); i++ )
80 if ( traj_vip[i].size() )
83 if ( vpImagePoint::distance( vip[i], traj_vip[i].back() ) > 1. )
85 traj_vip[i].push_back( vip[i] );
90 traj_vip[i].push_back( vip[i] );
93 for (
size_t i = 0; i < vip.size(); i++ )
95 for (
size_t j = 1; j < traj_vip[i].size(); j++ )
97 vpDisplay::displayLine( I, traj_vip[i][j - 1], traj_vip[i][j], vpColor::green, 2 );
103 main(
int argc,
char **argv )
105 double opt_tagSize = 0.08;
106 std::string opt_robot_ip =
"192.168.1.1";
107 std::string opt_eMc_filename =
"";
108 bool display_tag =
true;
109 int opt_quad_decimate = 2;
110 bool opt_verbose =
false;
111 bool opt_plot =
false;
112 bool opt_adaptive_gain =
false;
113 bool opt_task_sequencing =
false;
114 double convergence_threshold_t = 0.0005, convergence_threshold_tu = vpMath::rad( 0.5 );
116 for (
int i = 1; i < argc; i++ )
118 if ( std::string( argv[i] ) ==
"--tag_size" && i + 1 < argc )
120 opt_tagSize = std::stod( argv[i + 1] );
122 else if ( std::string( argv[i] ) ==
"--ip" && i + 1 < argc )
124 opt_robot_ip = std::string( argv[i + 1] );
126 else if ( std::string( argv[i] ) ==
"--eMc" && i + 1 < argc )
128 opt_eMc_filename = std::string( argv[i + 1] );
130 else if ( std::string( argv[i] ) ==
"--verbose" )
134 else if ( std::string( argv[i] ) ==
"--plot" )
138 else if ( std::string( argv[i] ) ==
"--adaptive_gain" )
140 opt_adaptive_gain =
true;
142 else if ( std::string( argv[i] ) ==
"--task_sequencing" )
144 opt_task_sequencing =
true;
146 else if ( std::string( argv[i] ) ==
"--quad_decimate" && i + 1 < argc )
148 opt_quad_decimate = std::stoi( argv[i + 1] );
150 else if ( std::string( argv[i] ) ==
"--no-convergence-threshold" )
152 convergence_threshold_t = 0.;
153 convergence_threshold_tu = 0.;
155 else if ( std::string( argv[i] ) ==
"--help" || std::string( argv[i] ) ==
"-h" )
158 << argv[0] <<
" [--ip <default " << opt_robot_ip <<
">] "
159 <<
"[--tag_size <marker size in meter; default " << opt_tagSize <<
">] [--eMc <eMc extrinsic file>] "
160 <<
"[--quad_decimate <decimation; default " << opt_quad_decimate
161 <<
">] [--adaptive_gain] [--plot] [--task_sequencing] [--no-convergence-threshold] [--verbose] [--help] [-h]"
171 std::cout <<
"Try to connect to robot ip: " << opt_robot_ip << std::endl;
172 robot.connect( opt_robot_ip );
173 std::cout <<
"Panda robot connected" << std::endl;
177 unsigned int width = 640, height = 480;
178 config.enable_stream( RS2_STREAM_COLOR, 640, 480, RS2_FORMAT_RGBA8, 30 );
179 config.enable_stream( RS2_STREAM_DEPTH, 640, 480, RS2_FORMAT_Z16, 30 );
180 config.enable_stream( RS2_STREAM_INFRARED, 640, 480, RS2_FORMAT_Y8, 30 );
181 std::cout <<
"Try to connect to Realsense camera " << std::endl;
183 std::cout <<
"Camera connected" << std::endl;
199 if ( !opt_eMc_filename.empty() )
201 ePc.loadYAML( opt_eMc_filename, ePc );
205 std::cout <<
"Warning, opt_eMc_filename is empty! Use hard coded values."
208 vpHomogeneousMatrix eMc( ePc );
209 std::cout <<
"eMc:\n" << eMc <<
"\n";
210 std::cout <<
"ePc:\n" << vpPoseVector(eMc).t() <<
"\n";
213 vpCameraParameters cam =
214 rs.getCameraParameters( RS2_STREAM_COLOR, vpCameraParameters::perspectiveProjWithDistortion );
215 std::cout <<
"cam:\n" << cam <<
"\n";
217 vpImage< unsigned char > I( height, width );
219 vpDisplayOpenCV dc( I, 10, 10,
"Color image" );
221 vpDetectorAprilTag::vpAprilTagFamily tagFamily = vpDetectorAprilTag::TAG_36h11;
222 vpDetectorAprilTag::vpPoseEstimationMethod poseEstimationMethod = vpDetectorAprilTag::HOMOGRAPHY_VIRTUAL_VS;
224 vpDetectorAprilTag detector( tagFamily );
225 detector.setAprilTagPoseEstimationMethod( poseEstimationMethod );
226 detector.setDisplayTag( display_tag );
227 detector.setAprilTagQuadDecimate( opt_quad_decimate );
230 vpHomogeneousMatrix cdMc, cMo, oMo;
233 vpHomogeneousMatrix cdMo( vpTranslationVector( 0, 0, opt_tagSize * 3 ),
234 vpRotationMatrix( { 1, 0, 0, 0, -1, 0, 0, 0, -1 } ) );
236 cdMc = cdMo * cMo.inverse();
237 vpFeatureTranslation t( vpFeatureTranslation::cdMc );
238 vpFeatureThetaU tu( vpFeatureThetaU::cdRc );
240 tu.buildFrom( cdMc );
242 vpFeatureTranslation td( vpFeatureTranslation::cdMc );
243 vpFeatureThetaU tud( vpFeatureThetaU::cdRc );
246 task.addFeature( t, td );
247 task.addFeature( tu, tud );
248 task.setServo( vpServo::EYEINHAND_CAMERA );
249 task.setInteractionMatrixType( vpServo::CURRENT );
251 if ( opt_adaptive_gain )
253 vpAdaptiveGain lambda( 1.5, 0.4, 30 );
254 task.setLambda( lambda );
258 task.setLambda( 0.5 );
261 vpPlot *plotter =
nullptr;
266 plotter =
new vpPlot( 2,
static_cast< int >( 250 * 2 ), 500,
static_cast< int >( I.getWidth() ) + 80, 10,
267 "Real time curves plotter" );
268 plotter->setTitle( 0,
"Visual features error" );
269 plotter->setTitle( 1,
"Camera velocities" );
270 plotter->initGraph( 0, 6 );
271 plotter->initGraph( 1, 6 );
272 plotter->setLegend( 0, 0,
"error_feat_tx" );
273 plotter->setLegend( 0, 1,
"error_feat_ty" );
274 plotter->setLegend( 0, 2,
"error_feat_tz" );
275 plotter->setLegend( 0, 3,
"error_feat_theta_ux" );
276 plotter->setLegend( 0, 4,
"error_feat_theta_uy" );
277 plotter->setLegend( 0, 5,
"error_feat_theta_uz" );
278 plotter->setLegend( 1, 0,
"vc_x" );
279 plotter->setLegend( 1, 1,
"vc_y" );
280 plotter->setLegend( 1, 2,
"vc_z" );
281 plotter->setLegend( 1, 3,
"wc_x" );
282 plotter->setLegend( 1, 4,
"wc_y" );
283 plotter->setLegend( 1, 5,
"wc_z" );
286 bool final_quit =
false;
287 bool has_converged =
false;
288 bool send_velocities =
false;
289 bool servo_started =
false;
290 std::vector< vpImagePoint > *traj_vip =
nullptr;
292 static double t_init_servo = vpTime::measureTimeMs();
294 robot.set_eMc( eMc );
295 robot.setRobotState( vpRobot::STATE_VELOCITY_CONTROL );
297 while ( !has_converged && !final_quit )
299 double t_start = vpTime::measureTimeMs();
303 vpDisplay::display( I );
305 std::vector< vpHomogeneousMatrix > cMo_vec;
306 detector.detect( I, opt_tagSize, cam, cMo_vec );
308 std::stringstream ss;
309 ss <<
"Left click to " << ( send_velocities ?
"stop the robot" :
"servo the robot" ) <<
", right click to quit.";
310 vpDisplay::displayText( I, 20, 20, ss.str(), vpColor::red );
312 vpColVector v_c( 6 );
315 if ( cMo_vec.size() == 1 )
319 static bool first_time =
true;
323 std::vector< vpHomogeneousMatrix > v_oMo( 2 ), v_cdMc( 2 );
324 v_oMo[1].buildFrom( 0, 0, 0, 0, 0, M_PI );
325 for (
size_t i = 0; i < 2; i++ )
327 v_cdMc[i] = cdMo * v_oMo[i] * cMo.inverse();
329 if ( std::fabs( v_cdMc[0].getThetaUVector().getTheta() ) <
330 std::fabs( v_cdMc[1].getThetaUVector().getTheta() ) )
336 std::cout <<
"Desired frame modified to avoid PI rotation of the camera" << std::endl;
342 cdMc = cdMo * oMo * cMo.inverse();
344 tu.buildFrom( cdMc );
346 if ( opt_task_sequencing )
348 if ( !servo_started )
350 if ( send_velocities )
352 servo_started =
true;
354 t_init_servo = vpTime::measureTimeMs();
356 v_c = task.computeControlLaw( ( vpTime::measureTimeMs() - t_init_servo ) / 1000. );
360 v_c = task.computeControlLaw();
364 vpDisplay::displayFrame( I, cdMo * oMo, cam, opt_tagSize / 1.5, vpColor::yellow, 2 );
365 vpDisplay::displayFrame( I, cMo, cam, opt_tagSize / 2, vpColor::none, 3 );
367 std::vector< vpImagePoint > vip = detector.getPolygon( 0 );
369 vip.push_back( detector.getCog( 0 ) );
373 traj_vip =
new std::vector< vpImagePoint >[vip.size()];
379 plotter->plot( 0, iter_plot, task.getError() );
380 plotter->plot( 1, iter_plot, v_c );
386 std::cout <<
"v_c: " << v_c.t() << std::endl;
389 vpTranslationVector cd_t_c = cdMc.getTranslationVector();
390 vpThetaUVector cd_tu_c = cdMc.getThetaUVector();
391 double error_tr = sqrt( cd_t_c.sumSquare() );
392 double error_tu = vpMath::deg( sqrt( cd_tu_c.sumSquare() ) );
395 ss <<
"error_t: " << error_tr;
396 vpDisplay::displayText( I, 20,
static_cast< int >( I.getWidth() ) - 150, ss.str(), vpColor::red );
398 ss <<
"error_tu: " << error_tu;
399 vpDisplay::displayText( I, 40,
static_cast< int >( I.getWidth() ) - 150, ss.str(), vpColor::red );
402 std::cout <<
"error translation: " << error_tr <<
" ; error rotation: " << error_tu << std::endl;
404 if ( error_tr < convergence_threshold_t && error_tu < convergence_threshold_tu )
406 has_converged =
true;
407 std::cout <<
"Servo task has converged" << std::endl;
409 vpDisplay::displayText( I, 100, 20,
"Servo task has converged", vpColor::red );
422 if ( !send_velocities )
428 robot.setVelocity( vpRobot::CAMERA_FRAME, v_c );
431 ss <<
"Loop time: " << vpTime::measureTimeMs() - t_start <<
" ms";
432 vpDisplay::displayText( I, 40, 20, ss.str(), vpColor::red );
433 vpDisplay::flush( I );
435 vpMouseButton::vpMouseButtonType button;
436 if ( vpDisplay::getClick( I, button,
false ) )
440 case vpMouseButton::button1:
441 send_velocities = !send_velocities;
444 case vpMouseButton::button3:
454 std::cout <<
"Stop the robot " << std::endl;
455 robot.setRobotState( vpRobot::STATE_STOP );
457 if ( opt_plot && plotter !=
nullptr )
465 while ( !final_quit )
468 vpDisplay::display( I );
470 vpDisplay::displayText( I, 20, 20,
"Click to quit the program.", vpColor::red );
471 vpDisplay::displayText( I, 40, 20,
"Visual servo converged.", vpColor::red );
473 if ( vpDisplay::getClick( I,
false ) )
478 vpDisplay::flush( I );
487 catch (
const vpException &e )
489 std::cout <<
"ViSP exception: " << e.what() << std::endl;
490 std::cout <<
"Stop the robot " << std::endl;
491 robot.setRobotState( vpRobot::STATE_STOP );
494 catch (
const franka::NetworkException &e )
496 std::cout <<
"Franka network exception: " << e.what() << std::endl;
497 std::cout <<
"Check if you are connected to the Franka robot"
498 <<
" or if you specified the right IP using --ip command line option set by default to 192.168.1.1. "
502 catch (
const std::exception &e )
504 std::cout <<
"Franka exception: " << e.what() << std::endl;
514 #if !defined( VISP_HAVE_REALSENSE2 )
515 std::cout <<
"Install librealsense-2.x" << std::endl;
517 #if ( VISP_CXX_STANDARD < VISP_CXX_STANDARD_11 )
518 std::cout <<
"Build ViSP with c++11 or higher compiler flag (cmake -DUSE_CXX_STANDARD=11)." << std::endl;
520 #if !defined( VISP_HAVE_FRANKA )
521 std::cout <<
"Install libfranka." << std::endl;