60 #include <visp3/core/vpCameraParameters.h>
61 #include <visp3/detection/vpDetectorAprilTag.h>
62 #include <visp3/gui/vpDisplayOpenCV.h>
63 #include <visp3/gui/vpPlot.h>
64 #include <visp3/io/vpImageIo.h>
65 #include <visp3/visual_features/vpFeatureBuilder.h>
66 #include <visp3/visual_features/vpFeaturePoint.h>
67 #include <visp3/vs/vpServo.h>
68 #include <visp3/vs/vpServoDisplay.h>
70 #include <visp3/robot/vpRobotFranka.h>
71 #include <visp3/sensor/vpRealSense2.h>
73 #if defined( VISP_HAVE_REALSENSE2 ) && ( VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11 ) && \
74 ( defined( VISP_HAVE_OPENCV ) ) && defined( VISP_HAVE_FRANKA )
78 std::vector< vpImagePoint > *traj_vip )
80 for (
size_t i = 0; i < vip.size(); i++ )
82 if ( traj_vip[i].size() )
85 if ( vpImagePoint::distance( vip[i], traj_vip[i].back() ) > 1. )
87 traj_vip[i].push_back( vip[i] );
92 traj_vip[i].push_back( vip[i] );
95 for (
size_t i = 0; i < vip.size(); i++ )
97 for (
size_t j = 1; j < traj_vip[i].size(); j++ )
99 vpDisplay::displayLine( I, traj_vip[i][j - 1], traj_vip[i][j], vpColor::green, 2 );
105 main(
int argc,
char **argv )
107 double opt_tagSize = 0.08;
108 std::string opt_robot_ip =
"192.168.1.1";
109 std::string opt_eMc_filename =
"";
110 bool display_tag =
true;
111 int opt_quad_decimate = 2;
112 bool opt_verbose =
false;
113 bool opt_plot =
false;
114 bool opt_adaptive_gain =
false;
115 bool opt_task_sequencing =
false;
116 double convergence_threshold = 0.00005;
118 for (
int i = 1; i < argc; i++ )
120 if ( std::string( argv[i] ) ==
"--tag_size" && i + 1 < argc )
122 opt_tagSize = std::stod( argv[i + 1] );
124 else if ( std::string( argv[i] ) ==
"--ip" && i + 1 < argc )
126 opt_robot_ip = std::string( argv[i + 1] );
128 else if ( std::string( argv[i] ) ==
"--eMc" && i + 1 < argc )
130 opt_eMc_filename = std::string( argv[i + 1] );
132 else if ( std::string( argv[i] ) ==
"--verbose" )
136 else if ( std::string( argv[i] ) ==
"--plot" )
140 else if ( std::string( argv[i] ) ==
"--adaptive_gain" )
142 opt_adaptive_gain =
true;
144 else if ( std::string( argv[i] ) ==
"--task_sequencing" )
146 opt_task_sequencing =
true;
148 else if ( std::string( argv[i] ) ==
"--quad_decimate" && i + 1 < argc )
150 opt_quad_decimate = std::stoi( argv[i + 1] );
152 else if ( std::string( argv[i] ) ==
"--no-convergence-threshold" )
154 convergence_threshold = 0.;
156 else if ( std::string( argv[i] ) ==
"--help" || std::string( argv[i] ) ==
"-h" )
159 << argv[0] <<
" [--ip <default " << opt_robot_ip <<
">] [--tag_size <marker size in meter; default "
160 << opt_tagSize <<
">] [--eMc <eMc extrinsic file>] "
161 <<
"[--quad_decimate <decimation; default " << opt_quad_decimate
162 <<
">] [--adaptive_gain] [--plot] [--task_sequencing] [--no-convergence-threshold] [--verbose] [--help] [-h]"
172 std::cout <<
"Try to connect to robot ip: " << opt_robot_ip << std::endl;
173 robot.connect( opt_robot_ip );
174 std::cout <<
"Panda robot connected" << std::endl;
178 unsigned int width = 640, height = 480;
179 config.enable_stream( RS2_STREAM_COLOR, 640, 480, RS2_FORMAT_RGBA8, 30 );
180 config.enable_stream( RS2_STREAM_DEPTH, 640, 480, RS2_FORMAT_Z16, 30 );
181 config.enable_stream( RS2_STREAM_INFRARED, 640, 480, RS2_FORMAT_Y8, 30 );
182 std::cout <<
"Try to connect to Realsense camera " << std::endl;
184 std::cout <<
"Camera connected" << std::endl;
200 if ( !opt_eMc_filename.empty() )
202 ePc.loadYAML( opt_eMc_filename, ePc );
206 std::cout <<
"Warning, opt_eMc_filename is empty! Use hard coded values."
209 vpHomogeneousMatrix eMc( ePc );
210 std::cout <<
"eMc:\n" << eMc <<
"\n";
211 std::cout <<
"ePc:\n" << vpPoseVector(eMc).t() <<
"\n";
214 vpCameraParameters cam =
215 rs.getCameraParameters( RS2_STREAM_COLOR, vpCameraParameters::perspectiveProjWithDistortion );
216 std::cout <<
"cam:\n" << cam <<
"\n";
218 vpImage< unsigned char > I( height, width );
220 vpDisplayOpenCV dc( I, 10, 10,
"Color image" );
222 vpDetectorAprilTag::vpAprilTagFamily tagFamily = vpDetectorAprilTag::TAG_36h11;
223 vpDetectorAprilTag::vpPoseEstimationMethod poseEstimationMethod = vpDetectorAprilTag::HOMOGRAPHY_VIRTUAL_VS;
225 vpDetectorAprilTag detector( tagFamily );
226 detector.setAprilTagPoseEstimationMethod( poseEstimationMethod );
227 detector.setDisplayTag( display_tag );
228 detector.setAprilTagQuadDecimate( opt_quad_decimate );
231 vpHomogeneousMatrix cMo, oMo;
234 vpHomogeneousMatrix cdMo( vpTranslationVector( 0, 0, opt_tagSize * 3 ),
235 vpRotationMatrix( { 1, 0, 0, 0, -1, 0, 0, 0, -1 } ) );
238 std::vector< vpFeaturePoint > p( 4 ), pd( 4 );
241 std::vector< vpPoint > point( 4 );
242 point[0].setWorldCoordinates( -opt_tagSize / 2., -opt_tagSize / 2., 0 );
243 point[1].setWorldCoordinates( opt_tagSize / 2., -opt_tagSize / 2., 0 );
244 point[2].setWorldCoordinates( opt_tagSize / 2., opt_tagSize / 2., 0 );
245 point[3].setWorldCoordinates( -opt_tagSize / 2., opt_tagSize / 2., 0 );
249 for (
size_t i = 0; i < p.size(); i++ )
251 task.addFeature( p[i], pd[i] );
253 task.setServo( vpServo::EYEINHAND_CAMERA );
254 task.setInteractionMatrixType( vpServo::CURRENT );
256 if ( opt_adaptive_gain )
258 vpAdaptiveGain lambda( 1.5, 0.4, 30 );
259 task.setLambda( lambda );
263 task.setLambda( 0.5 );
266 vpPlot *plotter =
nullptr;
271 plotter =
new vpPlot( 2,
static_cast< int >( 250 * 2 ), 500,
static_cast< int >( I.getWidth() ) + 80, 10,
272 "Real time curves plotter" );
273 plotter->setTitle( 0,
"Visual features error" );
274 plotter->setTitle( 1,
"Camera velocities" );
275 plotter->initGraph( 0, 8 );
276 plotter->initGraph( 1, 6 );
277 plotter->setLegend( 0, 0,
"error_feat_p1_x" );
278 plotter->setLegend( 0, 1,
"error_feat_p1_y" );
279 plotter->setLegend( 0, 2,
"error_feat_p2_x" );
280 plotter->setLegend( 0, 3,
"error_feat_p2_y" );
281 plotter->setLegend( 0, 4,
"error_feat_p3_x" );
282 plotter->setLegend( 0, 5,
"error_feat_p3_y" );
283 plotter->setLegend( 0, 6,
"error_feat_p4_x" );
284 plotter->setLegend( 0, 7,
"error_feat_p4_y" );
285 plotter->setLegend( 1, 0,
"vc_x" );
286 plotter->setLegend( 1, 1,
"vc_y" );
287 plotter->setLegend( 1, 2,
"vc_z" );
288 plotter->setLegend( 1, 3,
"wc_x" );
289 plotter->setLegend( 1, 4,
"wc_y" );
290 plotter->setLegend( 1, 5,
"wc_z" );
293 bool final_quit =
false;
294 bool has_converged =
false;
295 bool send_velocities =
false;
296 bool servo_started =
false;
297 std::vector< vpImagePoint > *traj_corners =
nullptr;
299 static double t_init_servo = vpTime::measureTimeMs();
301 robot.set_eMc( eMc );
302 robot.setRobotState( vpRobot::STATE_VELOCITY_CONTROL );
304 while ( !has_converged && !final_quit )
306 double t_start = vpTime::measureTimeMs();
310 vpDisplay::display( I );
312 std::vector< vpHomogeneousMatrix > cMo_vec;
313 detector.detect( I, opt_tagSize, cam, cMo_vec );
316 std::stringstream ss;
317 ss <<
"Left click to " << ( send_velocities ?
"stop the robot" :
"servo the robot" )
318 <<
", right click to quit.";
319 vpDisplay::displayText( I, 20, 20, ss.str(), vpColor::red );
322 vpColVector v_c( 6 );
325 if ( cMo_vec.size() == 1 )
329 static bool first_time =
true;
333 std::vector< vpHomogeneousMatrix > v_oMo( 2 ), v_cdMc( 2 );
334 v_oMo[1].buildFrom( 0, 0, 0, 0, 0, M_PI );
335 for (
size_t i = 0; i < 2; i++ )
337 v_cdMc[i] = cdMo * v_oMo[i] * cMo.inverse();
339 if ( std::fabs( v_cdMc[0].getThetaUVector().getTheta() ) <
340 std::fabs( v_cdMc[1].getThetaUVector().getTheta() ) )
346 std::cout <<
"Desired frame modified to avoid PI rotation of the camera" << std::endl;
351 for (
size_t i = 0; i < point.size(); i++ )
354 point[i].changeFrame( cdMo * oMo, cP );
355 point[i].projection( cP, p_ );
357 pd[i].set_x( p_[0] );
358 pd[i].set_y( p_[1] );
359 pd[i].set_Z( cP[2] );
364 std::vector< vpImagePoint > corners = detector.getPolygon( 0 );
367 for (
size_t i = 0; i < corners.size(); i++ )
370 vpFeatureBuilder::create( p[i], cam, corners[i] );
373 point[i].changeFrame( cMo, cP );
378 if ( opt_task_sequencing )
380 if ( !servo_started )
382 if ( send_velocities )
384 servo_started =
true;
386 t_init_servo = vpTime::measureTimeMs();
388 v_c = task.computeControlLaw( ( vpTime::measureTimeMs() - t_init_servo ) / 1000. );
392 v_c = task.computeControlLaw();
396 vpServoDisplay::display( task, cam, I );
397 for (
size_t i = 0; i < corners.size(); i++ )
399 std::stringstream ss;
402 vpDisplay::displayText( I, corners[i] + vpImagePoint( 15, 15 ), ss.str(), vpColor::red );
405 vpMeterPixelConversion::convertPoint( cam, pd[i].get_x(), pd[i].get_y(), ip );
406 vpDisplay::displayText( I, ip + vpImagePoint( 15, 15 ), ss.str(), vpColor::red );
410 traj_corners =
new std::vector< vpImagePoint >[corners.size()];
417 plotter->plot( 0, iter_plot, task.getError() );
418 plotter->plot( 1, iter_plot, v_c );
424 std::cout <<
"v_c: " << v_c.t() << std::endl;
427 double error = task.getError().sumSquare();
428 std::stringstream ss;
429 ss <<
"||error||: " << error;
430 vpDisplay::displayText( I, 20,
static_cast< int >( I.getWidth() ) - 150, ss.str(), vpColor::red );
433 std::cout << ss.str() << std::endl;
435 if ( !has_converged && error < convergence_threshold )
437 has_converged =
true;
438 std::cout <<
"Servo task has converged"
440 vpDisplay::displayText( I, 100, 20,
"Servo task has converged", vpColor::red );
452 if ( !send_velocities )
458 robot.setVelocity( vpRobot::CAMERA_FRAME, v_c );
461 std::stringstream ss;
462 ss <<
"Loop time: " << vpTime::measureTimeMs() - t_start <<
" ms";
463 vpDisplay::displayText( I, 40, 20, ss.str(), vpColor::red );
465 vpDisplay::flush( I );
467 vpMouseButton::vpMouseButtonType button;
468 if ( vpDisplay::getClick( I, button,
false ) )
472 case vpMouseButton::button1:
473 send_velocities = !send_velocities;
476 case vpMouseButton::button3:
486 std::cout <<
"Stop the robot " << std::endl;
487 robot.setRobotState( vpRobot::STATE_STOP );
489 if ( opt_plot && plotter !=
nullptr )
497 while ( !final_quit )
500 vpDisplay::display( I );
502 vpDisplay::displayText( I, 20, 20,
"Click to quit the program.", vpColor::red );
503 vpDisplay::displayText( I, 40, 20,
"Visual servo converged.", vpColor::red );
505 if ( vpDisplay::getClick( I,
false ) )
510 vpDisplay::flush( I );
515 delete[] traj_corners;
518 catch (
const vpException &e )
520 std::cout <<
"ViSP exception: " << e.what() << std::endl;
521 std::cout <<
"Stop the robot " << std::endl;
522 robot.setRobotState( vpRobot::STATE_STOP );
525 catch (
const franka::NetworkException &e )
527 std::cout <<
"Franka network exception: " << e.what() << std::endl;
528 std::cout <<
"Check if you are connected to the Franka robot"
529 <<
" or if you specified the right IP using --ip command line option set by default to 192.168.1.1. "
533 catch (
const std::exception &e )
535 std::cout <<
"Franka exception: " << e.what() << std::endl;
545 #if !defined( VISP_HAVE_REALSENSE2 )
546 std::cout <<
"Install librealsense-2.x" << std::endl;
548 #if ( VISP_CXX_STANDARD < VISP_CXX_STANDARD_11 )
549 std::cout <<
"Build ViSP with c++11 or higher compiler flag (cmake -DUSE_CXX_STANDARD=11)." << std::endl;
551 #if !defined( VISP_HAVE_FRANKA )
552 std::cout <<
"Install libfranka." << std::endl;