tutorial-franka-coppeliasim-dual-arm.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2021 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  *****************************************************************************/
32 
34 
35 #include <iostream>
36 
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>
46 
47 #include <visp_ros/vpROSGrabber.h>
49 
50 #include <geometry_msgs/WrenchStamped.h>
51 
52 void
53 display_point_trajectory( const vpImage< unsigned char > &I, const std::vector< vpImagePoint > &vip,
54  std::vector< vpImagePoint > *traj_vip )
55 {
56  for ( size_t i = 0; i < vip.size(); i++ )
57  {
58  if ( traj_vip[i].size() )
59  {
60  // Add the point only if distance with the previous > 1 pixel
61  if ( vpImagePoint::distance( vip[i], traj_vip[i].back() ) > 1. )
62  {
63  traj_vip[i].push_back( vip[i] );
64  }
65  }
66  else
67  {
68  traj_vip[i].push_back( vip[i] );
69  }
70  }
71  for ( size_t i = 0; i < vip.size(); i++ )
72  {
73  for ( size_t j = 1; j < traj_vip[i].size(); j++ )
74  {
75  vpDisplay::displayLine( I, traj_vip[i][j - 1], traj_vip[i][j], vpColor::green, 2 );
76  }
77  }
78 }
79 
80 vpMatrix
81 Ta( const vpHomogeneousMatrix &edMe )
82 {
83  vpMatrix Lx( 6, 6 ), Lw( 3, 3 ), skew_u( 3, 3 );
84 
85  Lx.eye();
86  vpThetaUVector tu( edMe );
87 
88  vpColVector u;
89  double theta;
90 
91  tu.extract( theta, u );
92  skew_u = vpColVector::skew( u );
93  Lw.eye();
94  if ( theta != 0.0 )
95  {
96  Lw -= 0.5 * theta * skew_u;
97  Lw += ( 1 - ( ( vpMath::sinc( theta ) ) / ( vpMath::sqr( vpMath::sinc( theta * 0.5 ) ) ) ) ) * skew_u * skew_u;
98  }
99 
100  Lx.insert( Lw, 3, 3 );
101 
102  return Lx;
103 }
104 
105 vpColVector We( 6, 0 );
106 std::mutex shared_data;
107 
108 void
109 Wrench_callback( const geometry_msgs::WrenchStamped &sensor_wrench )
110 {
111  std::lock_guard< std::mutex > lock( shared_data );
112  We[0] = sensor_wrench.wrench.force.x;
113  We[1] = sensor_wrench.wrench.force.y;
114  We[2] = sensor_wrench.wrench.force.z;
115  We[3] = sensor_wrench.wrench.torque.x;
116  We[4] = sensor_wrench.wrench.torque.y;
117  We[5] = sensor_wrench.wrench.torque.z;
118  return;
119 }
120 
121 vpMatrix
122 compute_interaction_matrix_3D( const vpHomogeneousMatrix &cdMc )
123 {
124  vpMatrix Lx( 6, 6 ), Lw( 3, 3 ), skew_u( 3, 3 );
125 
126  vpRotationMatrix cdRc( cdMc );
127  vpThetaUVector tu( cdMc );
128 
129  vpColVector u;
130  double theta;
131 
132  tu.extract( theta, u );
133  skew_u = vpColVector::skew( u );
134  Lw.eye();
135  Lw += 0.5 * theta * skew_u;
136  Lw += ( 1 - ( ( vpMath::sinc( theta ) ) / ( vpMath::sqr( vpMath::sinc( theta * 0.5 ) ) ) ) ) * skew_u * skew_u;
137 
138  Lx.insert( cdRc, 0, 0 );
139  Lx.insert( Lw, 3, 3 );
140 
141  return Lx;
142 }
143 
144 int
145 main( int argc, char **argv )
146 {
147  double opt_tagSize = 0.08;
148  bool display_tag = true;
149  int opt_quad_decimate = 2;
150  bool opt_verbose = false;
151  bool opt_plot = false;
152  bool opt_adaptive_gain = false;
153  double convergence_threshold_t = 0.005, convergence_threshold_tu = 0.5;
154  bool opt_coppeliasim_sync_mode = false;
155 
156  for ( int i = 1; i < argc; i++ )
157  {
158  if ( std::string( argv[i] ) == "--tag_size" && i + 1 < argc )
159  {
160  opt_tagSize = std::stod( argv[i + 1] );
161  }
162  else if ( std::string( argv[i] ) == "--verbose" || std::string( argv[i] ) == "-v" )
163  {
164  opt_verbose = true;
165  }
166  else if ( std::string( argv[i] ) == "--plot" )
167  {
168  opt_plot = true;
169  }
170  else if ( std::string( argv[i] ) == "--adaptive_gain" )
171  {
172  opt_adaptive_gain = true;
173  }
174  else if ( std::string( argv[i] ) == "--quad_decimate" && i + 1 < argc )
175  {
176  opt_quad_decimate = std::stoi( argv[i + 1] );
177  }
178  else if ( std::string( argv[i] ) == "--no-convergence-threshold" )
179  {
180  convergence_threshold_t = 0.;
181  convergence_threshold_tu = 0.;
182  }
183  else if ( std::string( argv[i] ) == "--enable-coppeliasim-sync-mode" )
184  {
185  opt_coppeliasim_sync_mode = true;
186  }
187  else if ( std::string( argv[i] ) == "--help" || std::string( argv[i] ) == "-h" )
188  {
189  std::cout << argv[0] << "[--tag_size <marker size in meter; default " << opt_tagSize << ">] "
190  << "[--quad_decimate <decimation; default " << opt_quad_decimate << ">] "
191  << "[--adaptive_gain] "
192  << "[--plot] "
193  << "[--task_sequencing] "
194  << "[--no-convergence-threshold] "
195  << "[--enable-coppeliasim-sync-mode] "
196  << "[--verbose] [-v] "
197  << "[--help] [-h]" << std::endl;
198  ;
199  return EXIT_SUCCESS;
200  }
201  }
202 
203  try
204  {
205  //------------------------------------------------------------------------//
206  //------------------------------------------------------------------------//
207  // ROS node
208  ros::init( argc, argv, "visp_ros" );
209  ros::NodeHandlePtr n = boost::make_shared< ros::NodeHandle >();
210  ros::Rate loop_rate( 1000 );
211  ros::spinOnce();
212 
213  ros::Subscriber sub_wrench = n->subscribe( "/coppeliasim/franka/right_arm/ft_sensor", 1, Wrench_callback );
214 
215  vpROSRobotFrankaCoppeliasim right_arm, left_arm;
216  right_arm.setVerbose( opt_verbose );
217  right_arm.connect( "right_arm" );
218  left_arm.setVerbose( opt_verbose );
219  left_arm.connect( "left_arm" );
220 
221  std::cout << "Coppeliasim sync mode enabled: " << ( opt_coppeliasim_sync_mode ? "yes" : "no" ) << std::endl;
222  right_arm.coppeliasimStopSimulation(); // Allows to reset simulation, moving the robot to initial position
223  right_arm.setCoppeliasimSyncMode( false );
224  left_arm.setCoppeliasimSyncMode( false );
225  right_arm.coppeliasimStartSimulation();
226 
227  vpHomogeneousMatrix bMfra( vpTranslationVector( 0.040, -0.03, 0.17 ),
228  vpRotationMatrix( { 1, 0, 0, 0, 0, -1, 0, 1, 0 } ) );
229  vpHomogeneousMatrix bMfla( vpTranslationVector( 0.040, 0.03, 0.17 ),
230  vpRotationMatrix( { 1, 0, 0, 0, 0, 1, 0, -1, 0 } ) );
231 
232  vpImage< unsigned char > I;
233  vpROSGrabber g;
234  g.setImageTopic( "/coppeliasim/franka/camera/image" );
235  g.setCameraInfoTopic( "/coppeliasim/franka/camera/camera_info" );
236  g.open( argc, argv );
237 
238  g.acquire( I );
239 
240  std::cout << "Image size: " << I.getWidth() << " x " << I.getHeight() << std::endl;
241  vpCameraParameters cam;
242 
243  g.getCameraInfo( cam );
244  std::cout << cam << std::endl;
245  vpDisplayOpenCV dc( I, 10, 10, "Color image" );
246 
247  vpDetectorAprilTag::vpAprilTagFamily tagFamily = vpDetectorAprilTag::TAG_36h11;
248  vpDetectorAprilTag::vpPoseEstimationMethod poseEstimationMethod = vpDetectorAprilTag::HOMOGRAPHY_VIRTUAL_VS;
249  vpDetectorAprilTag detector( tagFamily );
250  detector.setAprilTagPoseEstimationMethod( poseEstimationMethod );
251  detector.setDisplayTag( display_tag );
252  detector.setAprilTagQuadDecimate( opt_quad_decimate );
253 
254  // Servo
255  vpHomogeneousMatrix ccMo, cMo, oMo, ccMc, cdMcc, wMo, wMt;
256  // Desired pose used to compute the desired features
257  vpHomogeneousMatrix cdMo( vpTranslationVector( 0.0, 0.0, 0.2 ),
258  vpRotationMatrix( { 1, 0, 0, 0, -1, 0, 0, 0, -1 } ) );
259 
260  // Create visual features
261  vpFeatureTranslation t( vpFeatureTranslation::cdMc );
262  vpFeatureThetaU tu( vpFeatureThetaU::cdRc );
263  t.buildFrom( ccMc );
264  tu.buildFrom( ccMc );
265 
266  vpFeatureTranslation td( vpFeatureTranslation::cdMc );
267  vpFeatureThetaU tud( vpFeatureThetaU::cdRc );
268 
269  vpServo task;
270  // Add the visual features
271  task.addFeature( t, td );
272  task.addFeature( tu, tud );
273 
274  task.setServo( vpServo::EYEINHAND_CAMERA );
275  task.setInteractionMatrixType( vpServo::CURRENT );
276 
277  if ( opt_adaptive_gain )
278  {
279  std::cout << "Enable adaptive gain" << std::endl;
280  vpAdaptiveGain lambda( 4, 1.2, 25 ); // lambda(0)=4, lambda(oo)=1.2 and lambda'(0)=25
281  task.setLambda( lambda );
282  }
283  else
284  {
285  task.setLambda( 1.2 );
286  }
287 
288  vpPlot *plotter = nullptr;
289  vpPlot *plotter_left = nullptr;
290 
291  if ( opt_plot )
292  {
293  plotter = new vpPlot( 3, static_cast< int >( 250 * 2 ), 600, static_cast< int >( I.getWidth() ) + 80, 10,
294  "Real time curves plotter" );
295  plotter->setTitle( 0, "Visual features error" );
296  plotter->setTitle( 1, "Camera velocities" );
297  plotter->setTitle( 2, "Measured wrench" );
298  plotter->initGraph( 0, 6 );
299  plotter->initGraph( 1, 6 );
300  plotter->initGraph( 2, 6 );
301  plotter->setLegend( 0, 0, "error_feat_tx" );
302  plotter->setLegend( 0, 1, "error_feat_ty" );
303  plotter->setLegend( 0, 2, "error_feat_tz" );
304  plotter->setLegend( 0, 3, "error_feat_theta_ux" );
305  plotter->setLegend( 0, 4, "error_feat_theta_uy" );
306  plotter->setLegend( 0, 5, "error_feat_theta_uz" );
307  plotter->setLegend( 1, 0, "vc_x" );
308  plotter->setLegend( 1, 1, "vc_y" );
309  plotter->setLegend( 1, 2, "vc_z" );
310  plotter->setLegend( 1, 3, "wc_x" );
311  plotter->setLegend( 1, 4, "wc_y" );
312  plotter->setLegend( 1, 5, "wc_z" );
313  plotter->setLegend( 2, 0, "F_x" );
314  plotter->setLegend( 2, 1, "F_y" );
315  plotter->setLegend( 2, 2, "F_z" );
316  plotter->setLegend( 2, 3, "Tau_x" );
317  plotter->setLegend( 2, 4, "Tau_y" );
318  plotter->setLegend( 2, 5, "Tau_z" );
319 
320  plotter_left = new vpPlot( 4, 500, 600, 10, 10, "Real time curves plotter" );
321  plotter_left->setTitle( 0, "EE Pose [m] - [rad]" );
322  plotter_left->initGraph( 0, 6 );
323  plotter_left->setLegend( 0, 0, "x" );
324  plotter_left->setLegend( 0, 1, "y" );
325  plotter_left->setLegend( 0, 2, "z" );
326  plotter_left->setLegend( 0, 3, "tu_x" );
327  plotter_left->setLegend( 0, 4, "tu_y" );
328  plotter_left->setLegend( 0, 5, "tu_z" );
329 
330  plotter_left->setTitle( 1, "EE pose error [m] - [rad]" );
331  plotter_left->initGraph( 1, 6 );
332  plotter_left->setLegend( 1, 0, "e_x" );
333  plotter_left->setLegend( 1, 1, "e_y" );
334  plotter_left->setLegend( 1, 2, "e_z" );
335  plotter_left->setLegend( 1, 3, "e_tu_x" );
336  plotter_left->setLegend( 1, 4, "e_tu_y" );
337  plotter_left->setLegend( 1, 5, "e_tu_z" );
338 
339  plotter_left->setTitle( 2, "Joint torque command [Nm]" );
340  plotter_left->initGraph( 2, 7 );
341  plotter_left->setLegend( 2, 0, "Tau1" );
342  plotter_left->setLegend( 2, 1, "Tau2" );
343  plotter_left->setLegend( 2, 2, "Tau3" );
344  plotter_left->setLegend( 2, 3, "Tau4" );
345  plotter_left->setLegend( 2, 4, "Tau5" );
346  plotter_left->setLegend( 2, 5, "Tau6" );
347  plotter_left->setLegend( 2, 6, "Tau7" );
348 
349  plotter_left->setTitle( 3, "Pose error norm [rad]" );
350  plotter_left->initGraph( 3, 1 );
351  plotter_left->setLegend( 3, 0, "||e||" ); // change this
352  }
353 
354  bool final_quit = false;
355  bool has_converged = false;
356  bool send_cmd = false;
357  bool restart = false;
358  std::vector< vpImagePoint > *traj_corners = nullptr; // To memorize point trajectory
359 
360  double sim_time = right_arm.getCoppeliasimSimulationTime();
361  double sim_time_prev = sim_time;
362  double sim_time_init_servo = sim_time;
363  double sim_time_img = sim_time;
364  double sim_time_img_prev = sim_time;
365  double sim_time_start = sim_time;
366  double sim_time_convergence = sim_time;
367  double dt = 0.0;
368 
369  vpMatrix K( 6, 6 ), D( 6, 6 );
370  double wp = 50;
371  double wo = 20;
372  K.diag( { wp * wp, wp * wp, wp * wp, wo * wo, wo * wo, wo * wo } );
373  D.diag( { 2 * wp, 2 * wp, 2 * wp, 2 * wo, 2 * wo, 2 * wo } );
374 
375  double c_time = 0.0;
376  double mu = 2.0;
377 
378  std::cout << "eMc:\n" << right_arm.get_eMc() << std::endl;
379 
380  vpColVector v_c( 6, 0 ), q( 7, 0 ), dq( 7, 0 ), tau_d( 7, 0 ), C( 7, 0 ), pos( 6, 0 ), F( 7, 0 ), tau_d0( 7, 0 ),
381  tau_cmd( 7, 0 ), x_e( 6, 0 ), dx_e( 6, 0 ), dx_ed( 6, 0 ), ddx_ed( 6, 0 );
382  vpMatrix J( 6, 7 ), Ja( 6, 7 ), dJa( 6, 7 ), Ja_old( 6, 7 ), B( 7, 7 ), I7( 7, 7 ), Ja_pinv_B_t( 6, 7 ), Ls( 6, 6 );
383 
384  I7.eye();
385 
386  right_arm.setRobotState( vpRobot::STATE_VELOCITY_CONTROL );
387  left_arm.setRobotState( vpRobot::STATE_FORCE_TORQUE_CONTROL );
388 
389  right_arm.setCoppeliasimSyncMode( opt_coppeliasim_sync_mode );
390  left_arm.setCoppeliasimSyncMode( opt_coppeliasim_sync_mode );
391 
392  vpRotationMatrix wRed0( { 1, 0, 0, 0, -1, 0, 0, 0, -1 } );
393  vpHomogeneousMatrix wMed0( vpTranslationVector( 0.5, 0.0, 0.0 ), wRed0 );
394  vpHomogeneousMatrix wMed;
395  wMed = wMed0;
396 
397  std::atomic_bool admittance_thread_running{ true };
398  bool init_done = false;
399 
400  vpHomogeneousMatrix ftTee;
401  // the FT sensor frame is coincident with the flange frame in Coppeliasim model
402  // then the transformation between flange and end-effector is the same than
403  // the transformation between the FT sensor and the end-effector
404  ftTee = right_arm.get_flMe();
405  std::cout << "ftTee:\n" << ftTee << "\n";
406 
407  vpVelocityTwistMatrix cTe;
408  cTe.buildFrom( right_arm.get_eMc().inverse() );
409 
410  vpForceTwistMatrix cFee, eeFft, eeFc;
411  cFee.buildFrom( right_arm.get_eMc().inverse() );
412  eeFc.buildFrom( right_arm.get_eMc() );
413  eeFft.buildFrom( ftTee.inverse() );
414 
415  // Admittance parameters
416  vpColVector dde_s( 6, 0 ), de_s( 6, 0 ), e_s( 6, 0 ), d_err( 6, 0 ), err( 6, 0 ), old_err( 6, 0 );
417  vpMatrix Ks( 6, 6 ), Ds( 6, 6 ), Be( 6, 6 ), Bc_inv( 6, 6 ), I3( 3, 3 );
418  Ks.diag( 100 );
419  Ds.diag( 100 );
420 
421  I3.eye();
422  Be.insert( 1 * I3, 0, 0 ); // mass
423  Be.insert( 0.1 * I3, 3, 3 ); // inertia
424  // in this way we achieve Isotropic behavior on the ee frame
425  Bc_inv = cTe * Be.inverseByCholesky() * ( (vpMatrix)cTe ).t();
426 
427  vpColVector r( 3, 0 ), wFcog( 3, 0 ), ft_load( 6, 0 ), ft_meas( 6, 0 ), cfc_meas( 6, 0 ), Fs( 6, 0 );
428  double m = right_arm.get_tool_mass(); // [kg]
429  wFcog[2] = -9.81 * m;
430  r = right_arm.get_flMcom().getTranslationVector();
431 
432  std::thread fast_thread( [&]() {
433  std::cout << "fast_thread: started... \n" << std::endl;
434  try
435  {
436  while ( admittance_thread_running )
437  {
438  if ( init_done )
439  {
440 
441  sim_time = right_arm.getCoppeliasimSimulationTime();
442  dt = sim_time - sim_time_prev;
443  sim_time_prev = sim_time;
444  // std::cout << "dt: " << dt<< std::endl;
445 
446  vpColVector aux( 3, 0 );
447  aux = ( ( bMfra * right_arm.get_fMe() * right_arm.get_flMe().inverse() ).inverse() ).getRotationMatrix() *
448  wFcog;
449  ft_load[0] = aux[0];
450  ft_load[1] = aux[1];
451  ft_load[2] = aux[2];
452  aux = vpColVector::skew( r ) * aux;
453  ft_load[3] = aux[0];
454  ft_load[4] = aux[1];
455  ft_load[5] = aux[2];
456  ft_meas = We - ft_load;
457 
458  shared_data.lock();
459  cfc_meas = cFee * eeFft * ft_meas;
460  task.computeControlLaw();
461  Ls = compute_interaction_matrix_3D( cdMcc );
462 
463  Fs = Ls * Bc_inv * cfc_meas;
464 
465  // admittance law
466  dde_s = -Ks * e_s - Ds * de_s + Fs;
467  de_s += dde_s * dt;
468  e_s += de_s * dt;
469 
470  cdMcc.insert( (vpTranslationVector)e_s.extract( 0, 3 ) );
471  if ( sqrt( e_s.extract( 3, 3 ).sumSquare() ) != 0.0 )
472  {
473  vpRotationMatrix R_aux;
474  R_aux.buildFrom( (vpThetaUVector)e_s.extract( 3, 3 ) );
475  cdMcc.insert( R_aux );
476  }
477  else
478  {
479  cdMcc.insert( vpRotationMatrix() );
480  }
481  ccMo = cdMcc.inverse() * cdMo;
482  ccMc = ccMo * oMo * cMo.inverse();
483  t.buildFrom( ccMc );
484  tu.buildFrom( ccMc );
485 
486  v_c = task.computeControlLaw();
487 
488  left_arm.getPosition( vpRobot::JOINT_STATE, q );
489  left_arm.getVelocity( vpRobot::JOINT_STATE, dq );
490  left_arm.getMass( B );
491  left_arm.getCoriolis( C );
492  left_arm.getFriction( F );
493  left_arm.get_fJe( J );
494 
495  if ( has_converged )
496  {
497  wMed[0][3] = wMed0[0][3] + 0.05 * sin( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) );
498  wMed[1][3] = wMed0[1][3] + 0.05 * ( 1 - cos( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) ) );
499  // wMed[2][3] = wMed0[2][3] + 0.05*sin(2*M_PI*0.5*(sim_time - sim_time_convergence));
500 
501  dx_ed[0] = 2 * M_PI * 0.3 * 0.05 * cos( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) );
502  dx_ed[1] = 2 * M_PI * 0.3 * 0.05 * sin( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) );
503  // dx_ed[2] = 2*M_PI*0.5*0.05*cos(2*M_PI*0.5*(sim_time - sim_time_convergence));
504 
505  ddx_ed[0] =
506  -2 * M_PI * 0.3 * 2 * M_PI * 0.3 * 0.05 * sin( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) );
507  ddx_ed[1] =
508  2 * M_PI * 0.3 * 2 * M_PI * 0.3 * 0.05 * cos( 2 * M_PI * 0.3 * ( sim_time - sim_time_convergence ) );
509  // ddx_ed[2] = -2*M_PI*0.5*2*M_PI*0.5*0.05*sin(2*M_PI*0.5*(sim_time -
510  // sim_time_convergence));
511  }
512 
513  vpMatrix RR( 6, 6 );
514  RR.insert( wMed.getRotationMatrix().t(), 0, 0 );
515  RR.insert( wMed.getRotationMatrix().t(), 3, 3 );
516 
517  x_e = (vpColVector)vpPoseVector( wMed.inverse() * left_arm.get_fMe() );
518  Ja = Ta( wMed.inverse() * left_arm.get_fMe() ) * RR * J;
519 
520  dx_e = Ta( wMed.inverse() * left_arm.get_fMe() ) * RR * ( dx_ed - J * dq );
521 
522  if ( dt != 0 )
523  {
524  dJa = ( Ja - Ja_old ) / dt;
525  }
526  else
527  {
528  dJa = 0;
529  }
530  Ja_old = Ja;
531 
532  Ja_pinv_B_t = ( Ja * B.inverseByCholesky() * Ja.t() ).inverseByCholesky() * Ja * B.inverseByCholesky();
533 
534  // Compute the control law
535  tau_d = B * Ja.pseudoInverse() * ( -K * ( x_e ) + D * (dx_e)-dJa * dq + ddx_ed ) + C + F -
536  ( I7 - Ja.t() * Ja_pinv_B_t ) * B * dq * 100;
537 
538  if ( !send_cmd )
539  {
540  v_c = 0; // Stop the robot
541  tau_cmd = 0;
542  restart = true;
543  }
544  else
545  {
546  if ( restart )
547  {
548  c_time = sim_time;
549  tau_d0 = tau_d;
550  restart = false;
551  }
552  tau_cmd = tau_d - tau_d0 * std::exp( -mu * ( sim_time - c_time ) );
553  }
554 
555  right_arm.setVelocity( vpRobot::CAMERA_FRAME, v_c );
556  left_arm.setForceTorque( vpRobot::JOINT_STATE, tau_cmd );
557 
558  shared_data.unlock();
559 
560  } // end init_done
561  right_arm.wait( sim_time, 0.002 );
562  } // end while
563  }
564  catch ( const vpException &e )
565  {
566  std::cout << "ViSP exception: " << e.what() << std::endl;
567  admittance_thread_running = false;
568  }
569  catch ( ... )
570  {
571  std::cout << "Something wrong happens: " << std::endl;
572  admittance_thread_running = false;
573  }
574  std::cout << "fast_thread: exiting..." << std::endl;
575  final_quit = true;
576  } );
577 
578  // control loop
579  while ( !final_quit )
580  {
581  g.acquire( I, sim_time_img );
582  vpDisplay::display( I );
583 
584  std::vector< vpHomogeneousMatrix > cMo_vec;
585  detector.detect( I, opt_tagSize, cam, cMo_vec );
586 
587  {
588  std::stringstream ss;
589  ss << "Left click to " << ( send_cmd ? "stop the robot" : "servo the robot" ) << ", right click to quit.";
590  vpDisplay::displayText( I, 20, 20, ss.str(), vpColor::red );
591  }
592 
593  // Only one tag is detected
594  if ( cMo_vec.size() == 1 )
595  {
596  shared_data.lock();
597  cMo = cMo_vec[0];
598  if ( !init_done )
599  {
600  // Introduce security wrt tag positionning in order to avoid PI rotation
601  std::vector< vpHomogeneousMatrix > v_oMo( 2 ), v_cdMc( 2 );
602  v_oMo[1].buildFrom( 0, 0, 0, 0, 0, M_PI );
603  for ( size_t i = 0; i < 2; i++ )
604  {
605  v_cdMc[i] = cdMo * v_oMo[i] * cMo.inverse();
606  }
607  if ( std::fabs( v_cdMc[0].getThetaUVector().getTheta() ) <
608  std::fabs( v_cdMc[1].getThetaUVector().getTheta() ) )
609  {
610  oMo = v_oMo[0];
611  }
612  else
613  {
614  std::cout << "Desired frame modified to avoid PI rotation of the camera" << std::endl;
615  oMo = v_oMo[1]; // Introduce PI rotation
616  }
617  sim_time_start = sim_time;
618  ccMo = cdMo;
619  } // end first_time
620 
621  // Update visual features
622  ccMc = ccMo * oMo * cMo.inverse();
623  t.buildFrom( ccMc );
624  tu.buildFrom( ccMc );
625 
626  shared_data.unlock();
627 
628  // Display the current and desired feature points in the image display
629  // Display desired and current pose features
630  vpDisplay::displayFrame( I, cdMo * oMo, cam, opt_tagSize / 1.5, vpColor::yellow, 2 );
631  vpDisplay::displayFrame( I, ccMo * oMo, cam, opt_tagSize / 2, vpColor::none, 3 );
632  vpDisplay::displayFrame( I, cMo, cam, opt_tagSize / 2, vpColor::none, 3 );
633 
634  // Get tag corners
635  std::vector< vpImagePoint > corners = detector.getPolygon( 0 );
636 
637  // Get the tag cog corresponding to the projection of the tag frame in the image
638  corners.push_back( detector.getCog( 0 ) );
639  // Display the trajectory of the points
640  if ( !init_done )
641  {
642  traj_corners = new std::vector< vpImagePoint >[corners.size()];
643  }
644 
645  // Display the trajectory of the points used as features
646  // display_point_trajectory( I, corners, traj_corners );
647 
648  vpTranslationVector cd_t_c = ccMc.getTranslationVector();
649  vpThetaUVector cd_tu_c = ccMc.getThetaUVector();
650  double error_tr = sqrt( cd_t_c.sumSquare() );
651  double error_tu = vpMath::deg( sqrt( cd_tu_c.sumSquare() ) );
652 
653  std::stringstream ss;
654  ss << "error_t [m]: " << error_tr;
655  vpDisplay::displayText( I, 20, static_cast< int >( I.getWidth() ) - 160, ss.str(), vpColor::red );
656  ss.str( "" );
657  ss << "error_tu [deg]: " << error_tu;
658  vpDisplay::displayText( I, 40, static_cast< int >( I.getWidth() ) - 160, ss.str(), vpColor::red );
659 
660  if ( !has_converged && error_tr < convergence_threshold_t && error_tu < convergence_threshold_tu )
661  {
662  has_converged = true;
663  sim_time_convergence = sim_time;
664  std::cout << "Servo task has converged \n";
665  vpDisplay::displayText( I, 100, 20, "Servo task has converged", vpColor::red );
666  }
667 
668  if ( !init_done )
669  {
670  init_done = true;
671  }
672  } // end if (cMo_vec.size() == 1)
673  else
674  {
675  v_c = 0; // Stop the robot
676  tau_cmd = 0;
677  }
678 
679  if ( opt_plot )
680  {
681  plotter->plot( 0, static_cast< double >( sim_time ), task.getError() );
682  plotter->plot( 1, static_cast< double >( sim_time ), v_c );
683  plotter->plot( 2, static_cast< double >( sim_time ), cfc_meas );
684 
685  plotter_left->plot( 0, sim_time, (vpColVector)vpPoseVector( bMfla * left_arm.get_fMe() ) );
686  plotter_left->plot( 1, sim_time, x_e );
687  plotter_left->plot( 2, sim_time, tau_cmd );
688  plotter_left->plot( 3, sim_time, vpColVector( 1, sqrt( x_e.sumSquare() ) ) );
689  }
690 
691  std::stringstream ss;
692  ss << "Loop time [s]: " << std::round( ( sim_time_img - sim_time_img_prev ) * 1000. ) / 1000.;
693  ss << " Simulation time [s]: " << sim_time_img;
694  sim_time_img_prev = sim_time_img;
695  vpDisplay::displayText( I, 40, 20, ss.str(), vpColor::red );
696 
697  vpMouseButton::vpMouseButtonType button;
698  if ( vpDisplay::getClick( I, button, false ) )
699  {
700  switch ( button )
701  {
702  case vpMouseButton::button1:
703  send_cmd = !send_cmd;
704  break;
705 
706  case vpMouseButton::button3:
707  final_quit = true;
708  v_c = 0;
709  tau_cmd = 0;
710  admittance_thread_running = false;
711  break;
712 
713  default:
714  break;
715  }
716  }
717 
718  vpDisplay::flush( I );
719  } // end while
720 
721  if ( opt_plot && plotter != nullptr && plotter_left != nullptr )
722  {
723  delete plotter;
724  plotter = nullptr;
725  delete plotter_left;
726  plotter_left = nullptr;
727  }
728  right_arm.coppeliasimStopSimulation();
729  right_arm.setRobotState( vpRobot::STATE_STOP );
730  left_arm.setRobotState( vpRobot::STATE_STOP );
731 
732  if ( !final_quit )
733  {
734  while ( !final_quit )
735  {
736  g.acquire( I );
737  vpDisplay::display( I );
738 
739  vpDisplay::displayText( I, 20, 20, "Click to quit the program.", vpColor::red );
740  vpDisplay::displayText( I, 40, 20, "Visual servo converged.", vpColor::red );
741 
742  if ( vpDisplay::getClick( I, false ) )
743  {
744  final_quit = true;
745  }
746 
747  vpDisplay::flush( I );
748  }
749  }
750  if ( fast_thread.joinable() )
751  {
752  fast_thread.join();
753  std::cout << "fast thread joined.. \n ";
754  }
755  if ( traj_corners )
756  {
757  delete[] traj_corners;
758  }
759  }
760  catch ( const vpException &e )
761  {
762  std::cout << "ViSP exception: " << e.what() << std::endl;
763  std::cout << "Stop the robot " << std::endl;
764  return EXIT_FAILURE;
765  }
766 
767  return 0;
768 }
boost::shared_ptr< NodeHandle >
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
vpRobotFrankaSim::get_flMe
vpHomogeneousMatrix get_flMe() const
Definition: vpRobotFrankaSim.cpp:376
vpROSGrabber::getCameraInfo
bool getCameraInfo(vpCameraParameters &cam)
Definition: vpROSGrabber.cpp:649
vpRobotFrankaSim::getPosition
virtual void getPosition(const vpRobot::vpControlFrameType frame, vpColVector &position)
Definition: vpRobotFrankaSim.cpp:417
vpRobotFrankaSim::setVelocity
virtual void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &vel)
Definition: vpRobotFrankaSim.cpp:683
vpROSGrabber
Class for cameras video capture for ROS cameras.
Definition: vpROSGrabber.h:104
compute_interaction_matrix_3D
vpMatrix compute_interaction_matrix_3D(const vpHomogeneousMatrix &cdMc)
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:122
Ta
vpMatrix Ta(const vpHomogeneousMatrix &edMe)
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:81
vpRobotFrankaSim::get_fJe
void get_fJe(vpMatrix &fJe)
Definition: vpRobotFrankaSim.cpp:264
vpROSRobotFrankaCoppeliasim
Definition: vpROSRobotFrankaCoppeliasim.h:87
ros::spinOnce
ROSCPP_DECL void spinOnce()
vpRobotFrankaSim::get_flMcom
vpHomogeneousMatrix get_flMcom() const
Definition: vpRobotFrankaSim.cpp:386
vpRobotFrankaSim::get_fMe
vpHomogeneousMatrix get_fMe(const vpColVector &q)
Definition: vpRobotFrankaSim.cpp:978
vpROSRobotFrankaCoppeliasim::setRobotState
vpRobot::vpRobotStateType setRobotState(vpRobot::vpRobotStateType newState)
Definition: vpROSRobotFrankaCoppeliasim.cpp:764
vpROSRobotFrankaCoppeliasim::wait
void wait(double timestamp_second, double duration_second)
Definition: vpROSRobotFrankaCoppeliasim.cpp:976
vpROSGrabber::open
void open(int argc, char **argv)
Definition: vpROSGrabber.cpp:98
vpRobotFrankaSim::setForceTorque
virtual void setForceTorque(const vpRobot::vpControlFrameType frame, const vpColVector &force)
Definition: vpRobotFrankaSim.cpp:875
vpRobotFrankaSim::setVerbose
void setVerbose(bool verbose)
Definition: vpRobotFrankaSim.h:111
vpROSRobotFrankaCoppeliasim.h
shared_data
std::mutex shared_data
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:106
vpROSRobotFrankaCoppeliasim::coppeliasimStopSimulation
void coppeliasimStopSimulation(double sleep_ms=1000.)
Definition: vpROSRobotFrankaCoppeliasim.cpp:268
display_point_trajectory
void display_point_trajectory(const vpImage< unsigned char > &I, const std::vector< vpImagePoint > &vip, std::vector< vpImagePoint > *traj_vip)
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:53
vpROSGrabber::setImageTopic
void setImageTopic(const std::string &topic_name)
Definition: vpROSGrabber.cpp:592
vpROSRobotFrankaCoppeliasim::getCoppeliasimSimulationTime
double getCoppeliasimSimulationTime()
Definition: vpROSRobotFrankaCoppeliasim.cpp:342
vpRobotFrankaSim::getMass
void getMass(vpMatrix &mass)
Definition: vpRobotFrankaSim.cpp:1019
vpROSGrabber::setCameraInfoTopic
void setCameraInfoTopic(const std::string &topic_name)
Definition: vpROSGrabber.cpp:579
vpROSRobotFrankaCoppeliasim::coppeliasimStartSimulation
void coppeliasimStartSimulation(double sleep_ms=1000.)
Definition: vpROSRobotFrankaCoppeliasim.cpp:248
vpRobotFrankaSim::getCoriolis
void getCoriolis(vpColVector &coriolis)
Definition: vpRobotFrankaSim.cpp:1042
vpRobotFrankaSim::get_tool_mass
double get_tool_mass() const
Definition: vpRobotFrankaSim.cpp:396
vpROSRobotFrankaCoppeliasim::setCoppeliasimSyncMode
void setCoppeliasimSyncMode(bool enable, double sleep_ms=1000.)
Definition: vpROSRobotFrankaCoppeliasim.cpp:209
Wrench_callback
void Wrench_callback(const geometry_msgs::WrenchStamped &sensor_wrench)
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:109
vpRobotFrankaSim::get_eMc
vpHomogeneousMatrix get_eMc() const
Definition: vpRobotFrankaSim.cpp:366
vpRobotFrankaSim::getFriction
void getFriction(vpColVector &friction)
Definition: vpRobotFrankaSim.cpp:144
ros::Rate
vpROSGrabber::acquire
void acquire(vpImage< unsigned char > &I)
Definition: vpROSGrabber.cpp:412
inverse
TFSIMD_FORCE_INLINE Quaternion inverse(const Quaternion &q)
vpROSGrabber.h
class for Camera video capture for ROS middleware.
vpROSRobotFrankaCoppeliasim::connect
void connect(const std::string &robot_ID="")
Definition: vpROSRobotFrankaCoppeliasim.cpp:132
main
int main(int argc, char **argv)
Definition: tutorial-franka-coppeliasim-dual-arm.cpp:145
ros::Subscriber
vpRobotFrankaSim::getVelocity
virtual void getVelocity(const vpRobot::vpControlFrameType frame, vpColVector &d_position)
Definition: vpRobotFrankaSim.cpp:627
We
vpColVector We(6, 0)


visp_ros
Author(s): Francois Pasteau, Fabien Spindler, Gatien Gaumerais, Alexander Oliva
autogenerated on Wed Mar 2 2022 01:13:33