Visual Servoing Platform  version 3.0.0
servoAfma4Point2DCamVelocityKalman.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See http://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * tests the control law
32  * eye-in-hand control
33  * velocity computed in the camera frame
34  *
35  * Authors:
36  * Eric Marchand
37  * Fabien Spindler
38  *
39  *****************************************************************************/
40 
59 #include <visp3/core/vpConfig.h>
60 #include <visp3/core/vpDebug.h> // Debug trace
61 #include <stdlib.h>
62 #if (defined (VISP_HAVE_AFMA4) && defined (VISP_HAVE_DC1394))
63 
64 #include <visp3/sensor/vp1394TwoGrabber.h>
65 #include <visp3/core/vpImage.h>
66 #include <visp3/core/vpDisplay.h>
67 #include <visp3/gui/vpDisplayX.h>
68 #include <visp3/gui/vpDisplayOpenCV.h>
69 #include <visp3/gui/vpDisplayGTK.h>
70 
71 #include <visp3/core/vpMath.h>
72 #include <visp3/core/vpHomogeneousMatrix.h>
73 #include <visp3/visual_features/vpFeaturePoint.h>
74 #include <visp3/core/vpPoint.h>
75 #include <visp3/vs/vpServo.h>
76 #include <visp3/visual_features/vpFeatureBuilder.h>
77 #include <visp3/robot/vpRobotAfma4.h>
78 #include <visp3/core/vpIoTools.h>
79 #include <visp3/core/vpException.h>
80 #include <visp3/vs/vpServoDisplay.h>
81 #include <visp3/io/vpParseArgv.h>
82 #include <visp3/blob/vpDot2.h>
83 #include <visp3/vs/vpAdaptiveGain.h>
84 #include <visp3/core/vpLinearKalmanFilterInstantiation.h>
85 
86 
87 // List of allowed command line options
88 #define GETOPTARGS "hK:l:"
89 
90 typedef enum {
91  K_NONE,
92  K_VELOCITY,
93  K_ACCELERATION
94 } KalmanType;
95 
105 void usage(const char *name, const char *badparam,
106  KalmanType &kalman)
107 {
108  fprintf(stdout, "\n\
109 Tests a control law with the following characteristics:\n\
110 - eye-in-hand control\n\
111 - camera velocity are computed\n\
112 - servo on 1 points.\n\
113 - Kalman filtering\n\
114  \n\
115 SYNOPSIS\n\
116  %s [-K <0|1|2|3>] [-h]\n", name);
117 
118  fprintf(stdout, "\n\
119 OPTIONS: Default\n\
120  -l <%%f> \n\
121  Set the constant gain. By default adaptive gain. \n\
122  \n\
123  -K <0|1|2> %d\n\
124  Kalman filtering:\n\
125  0: none\n\
126  1: velocity model\n\
127  2: acceleration model\n\
128  \n\
129  -h\n\
130  Print the help.\n", (int) kalman);
131 
132  if (badparam) {
133  fprintf(stderr, "ERROR: \n" );
134  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
135  }
136 
137 }
138 
153 bool getOptions(int argc, const char **argv, KalmanType &kalman,
154  bool &doAdaptativeGain,
155  vpAdaptiveGain &lambda) // gain lambda
156 {
157  const char *optarg;
158  int c;
159  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg)) > 1) {
160 
161  switch (c) {
162  case 'K':
163  kalman = (KalmanType) atoi(optarg);
164  break;
165  case 'l':
166  doAdaptativeGain = false;
167  lambda.initFromConstant( atof(optarg) );
168  break;
169  case 'h': usage(argv[0], NULL, kalman);
170  return false; break;
171 
172  default:
173  usage(argv[0], optarg, kalman);
174  return false; break;
175  }
176  }
177 
178  if ((c == 1) || (c == -1)) {
179  // standalone param or error
180  usage(argv[0], NULL, kalman);
181  std::cerr << "ERROR: " << std::endl;
182  std::cerr << " Bad argument " << optarg << std::endl << std::endl;
183  return false;
184  }
185 
186  return true;
187 }
188 
189 int
190 main(int argc, const char ** argv)
191 {
192  try {
193  KalmanType opt_kalman = K_NONE;
194  vpAdaptiveGain lambda; // Gain de la commande
195  bool doAdaptativeGain = true; // Compute adaptative gain
196  lambda.initStandard(4, 0.2, 40);
197  int opt_cam_frequency = 60; // 60 Hz
198 
199  // Read the command line options
200  if (getOptions(argc, argv, opt_kalman, doAdaptativeGain, lambda) == false) {
201  return (-1);
202  }
203 
204  // Log file creation in /tmp/$USERNAME/log.dat
205  // This file contains by line:
206  // - the 6 computed cam velocities (m/s, rad/s) to achieve the task
207  // - the 6 mesured joint velocities (m/s, rad/s)
208  // - the 6 mesured joint positions (m, rad)
209  // - the 2 values of s - s*
210  std::string username;
211  // Get the user login name
212  vpIoTools::getUserName(username);
213 
214  // Create a log filename to save velocities...
215  std::string logdirname;
216  logdirname ="/tmp/" + username;
217 
218  // Test if the output path exist. If no try to create it
219  if (vpIoTools::checkDirectory(logdirname) == false) {
220  try {
221  // Create the dirname
222  vpIoTools::makeDirectory(logdirname);
223  }
224  catch (...) {
225  std::cerr << std::endl
226  << "ERROR:" << std::endl;
227  std::cerr << " Cannot create " << logdirname << std::endl;
228  exit(-1);
229  }
230  }
231  std::string logfilename;
232  logfilename = logdirname + "/log.dat";
233 
234  // Open the log file name
235  std::ofstream flog(logfilename.c_str());
236 
237  vpServo task ;
238 
240  vp1394TwoGrabber g(false);
242  switch(opt_cam_frequency) {
243  case 15: g.setFramerate(vp1394TwoGrabber::vpFRAMERATE_15); break;
244  case 30: g.setFramerate(vp1394TwoGrabber::vpFRAMERATE_30); break;
245  case 60: g.setFramerate(vp1394TwoGrabber::vpFRAMERATE_60); break;
246  }
247  g.open(I) ;
248 
249  for (int i=0; i < 10; i++) // 10 acquisition to warm up the camera
250  g.acquire(I) ;
251 
252 #ifdef VISP_HAVE_X11
253  vpDisplayX display(I,100,100,"Current image") ;
254 #elif defined(VISP_HAVE_OPENCV)
255  vpDisplayOpenCV display(I,100,100,"Current image") ;
256 #elif defined(VISP_HAVE_GTK)
257  vpDisplayGTK display(I,100,100,"Current image") ;
258 #endif
259 
260  vpDisplay::display(I) ;
261  vpDisplay::flush(I) ;
262 
263  std::cout << std::endl ;
264  std::cout << "-------------------------------------------------------" << std::endl ;
265  std::cout << "Test program for target motion compensation using a Kalman filter " <<std::endl ;
266  std::cout << "Eye-in-hand task control, velocity computed in the camera frame" << std::endl ;
267  std::cout << "Task : servo a point \n" << std::endl ;
268 
269  // Kalman filtering
270  switch(opt_kalman) {
271  case K_NONE:
272  std::cout << "Servo with no target motion compensation (see -K option)\n";
273  break;
274  case K_VELOCITY:
275  std::cout << "Servo with target motion compensation using a Kalman filter\n"
276  << "with constant velocity modelization (see -K option)\n";
277  break;
278  case K_ACCELERATION:
279  std::cout << "Servo with target motion compensation using a Kalman filter\n"
280  << "with constant acceleration modelization (see -K option)\n";
281  break;
282  }
283  std::cout << "-------------------------------------------------------" << std::endl ;
284  std::cout << std::endl ;
285 
286  vpDot2 dot ;
287 
288  std::cout << "Click on the dot..." << std::endl;
289  dot.setGraphics(true);
290  dot.initTracking(I) ;
291  vpImagePoint cog;
292  cog = dot.getCog();
294  vpDisplay::flush(I);
295 
296  vpRobotAfma4 robot ;
297 
298  double px = 1000;
299  double py = 1000;
300  double u0 = I.getWidth() / 2.;
301  double v0 = I.getHeight() / 2.;
302 
303  vpCameraParameters cam(px, py, u0, v0);
304 
305  // Sets the current position of the visual feature
306  vpFeaturePoint p ;
307  vpFeatureBuilder::create(p, cam, dot) ;
308 
309  // Sets the desired position of the visual feature
310  vpFeaturePoint pd ;
311  pd.buildFrom(0,0,1) ;
312 
313  // Define the task
314  // - we want an eye-in-hand control law
315  // - robot is controlled in the camera frame
316  task.setServo(vpServo::EYEINHAND_CAMERA) ;
317 
318  // - we want to see a point on a point
319  std::cout << std::endl ;
320  task.addFeature(p,pd) ;
321 
322  // - set the gain
323  task.setLambda(lambda) ;
324 
325  // Display task information
326  // task.print() ;
327 
328  //--------------------------------------------------------------------------
330  //--------------------------------------------------------------------------
331 
334 
335  // Initialize the kalman filter
336  unsigned int nsignal = 2; // The two values of dedt
337  double rho = 0.3;
338  vpColVector sigma_state;
339  vpColVector sigma_measure(nsignal);
340  unsigned int state_size = 0; // Kalman state vector size
341 
342  switch(opt_kalman) {
343  case K_VELOCITY: {
344  // Set the constant velocity state model used for the filtering
346  state_size = kalman.getStateSize();
347  sigma_state.resize(state_size*nsignal);
348  sigma_state = 0.00001; // Same state variance for all signals
349  sigma_measure = 0.05; // Same measure variance for all the signals
350  double dummy = 0; // non used parameter dt for the velocity state model
351  kalman.initFilter(nsignal, sigma_state, sigma_measure, rho, dummy);
352 
353  break;
354  }
355  case K_ACCELERATION: {
356  // Set the constant acceleration state model used for the filtering
358  state_size = kalman.getStateSize();
359  sigma_state.resize(state_size*nsignal);
360  sigma_state = 0.00001; // Same variance for all the signals
361  sigma_measure = 0.05; // Same measure variance for all the signals
362  double dt = 1./opt_cam_frequency;
363  kalman.initFilter(nsignal, sigma_state, sigma_measure, rho, dt );
364  break;
365  }
366  default:
367  break;
368  }
369 
371 
372  int iter = 0 ;
373 
374  double t_0, t_1, Tv, Tv_0, Tv_1;
375  vpColVector vm(6), vm_0(6);
376  vpColVector v(6), v1(6), v2(6); // robot velocities
377  //task error
378  vpColVector err(2), err_0(2), err_1(2);
379  vpColVector dedt_filt(2), dedt_mes(2);
380 
381 
382  t_1 = vpTime::measureTimeMs(); // t_1: time at previous iter
383 
384  Tv_0 = 0;
385 
386  //
387  // Warning: In all varaible names,
388  // _0 means the value for the current iteration (t=0)
389  // _1 means the value for the previous iteration (t=-1)
390  // _2 means the value for the previous previous iteration (t=-2)
391  //
392  std::cout << "\nHit CTRL-C to stop the loop...\n" << std::flush;
393  for ( ; ; ) {
394  t_0 = vpTime::measureTimeMs(); // t_0: current time
395  // Temps de la boucle d'asservissement
396  Tv = (double)(t_0 - t_1) / 1000.0; //temps d'une iteration en s !
397  // std::cout << "time iter : " << Tv << std::endl;
398 
399  // Update time for next iteration
400  t_1 = t_0;
401 
403 
404  // Acquire a new image from the camera
405  g.acquire(I) ;
406 
407  // Display this image
408  vpDisplay::display(I) ;
409 
410  // Achieve the tracking of the dot in the image
411  dot.track(I) ;
412  vpImagePoint cog = dot.getCog();
413 
414  // Display a green cross at the center of gravity position in the image
416 
417  // Update the point feature from the dot location
418  vpFeatureBuilder::create(p, cam, dot);
419 
420  //----------------------------------------------------------------------
422  //----------------------------------------------------------------------
423  vm_0 = vm;
424 
425  // Update current loop time and previous one
426  Tv_1 = Tv_0;
427  Tv_0 = Tv;
428 
429  // Compute the visual servoing skew vector
430  v1 = task.computeControlLaw() ;
431 
432  err = task.error;
433 
435  if (iter==0){
436  err_0 = 0;
437  err_1 = 0;
438  dedt_mes = 0;
439  dedt_filt = 0;
440  }
441  else{
442  err_1 = err_0;
443  err_0 = err;
444 
445  dedt_mes = (err_0 - err_1)/(Tv_1) - task.J1*vm_0;
446  }
448  if (iter <= 1){
449  dedt_mes = 0;
450  }
451 
452  //----------------------------------------------------------------------
453  //----------------------- Kalman Filter Equations ----------------------
454  //----------------------------------------------------------------------
455  // Kalman filtering
456  switch(opt_kalman) {
457  case K_NONE:
458  dedt_filt = 0;
459  break;
460  case K_VELOCITY:
461  case K_ACCELERATION:
462  kalman.filter(dedt_mes);
463  for (unsigned int i=0; i < nsignal; i++) {
464  dedt_filt[i] = kalman.Xest[i*state_size];
465  }
466  break;
467  }
468 
470  vpMatrix J1p = task.getTaskJacobianPseudoInverse();
471  v2 = - J1p*dedt_filt;
472  // std::cout << "task J1p: " << J1p.t() << std::endl ;
473  // std::cout << "dedt_filt: " << dedt_filt.t() << std::endl ;
474 
475  v = v1 + v2;
476 
477  // Display the current and desired feature points in the image display
478  vpServoDisplay::display(task, cam, I) ;
479 
480 
481  // std::cout << "v2 : " << v2.t() << std::endl ;
482  // std::cout << "v1 : " << v1.t() << std::endl ;
483 
484  // std::cout << "v : " << v.t();
485 
486  // Apply the camera velocities to the robot
488 
489  // Save loop time
490  flog << Tv_0 << " ";
491 
492  // Save velocities applied to the robot in the log file
493  // v[0], v[1], v[2] correspond to camera translation velocities in m/s
494  // v[3], v[4], v[5] correspond to camera rotation velocities in rad/s
495  flog << v[0] << " " << v[1] << " " << v[2] << " "
496  << v[3] << " " << v[4] << " " << v[5] << " ";
497 
498  // Save feature error (s-s*) for the feature point. For this feature
499  // point, we have 2 errors (along x and y axis). This error is expressed
500  // in meters in the camera frame
501  flog << task.error[0] << " " << task.error[1] << " ";
502 
503  // Save feature error (s-s*) in pixels in the image.
504  flog << cog.get_u()-cam.get_u0() << " "
505  << cog.get_v()-cam.get_v0() << " ";
506 
507  // Save de/dt
508  flog << dedt_mes[0] << " " << dedt_mes[1] << " ";
509 
510  // Save de/dt filtered
511  flog << dedt_filt[0] << " " << dedt_filt[1] << " ";
512 
513  flog << std::endl;
514 
515  // Flush the display
516  vpDisplay::flush(I);
517 
518  iter ++;
519 
520  }
521 
522  flog.close() ; // Close the log file
523 
524  // Display task information
525  task.print() ;
526 
527  // Kill the task
528  task.kill();
529 
530  return 0;
531  }
532  catch(vpException e) {
533  std::cout << "Catch a ViSP exception: " << e << std::endl;
534  return 1;
535  }
536 
537 }
538 
539 
540 #else
541 int
542 main()
543 {
544  vpERROR_TRACE("You do not have an afma4 robot or a firewire framegrabber connected to your computer...");
545 }
546 #endif
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:92
double get_v() const
Definition: vpImagePoint.h:259
Adaptive gain computation.
unsigned int getStateSize()
double get_u0() const
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:335
unsigned int getWidth() const
Definition: vpImage.h:161
void initFilter(unsigned int nsignal, vpColVector &sigma_state, vpColVector &sigma_measure, double rho, double dt)
#define vpERROR_TRACE
Definition: vpDebug.h:391
void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &velocity)
double get_u() const
Definition: vpImagePoint.h:248
Define the X11 console to display images.
Definition: vpDisplayX.h:148
error that can be emited by ViSP classes.
Definition: vpException.h:73
Class that defines a 2D point visual feature which is composed by two parameters that are the cartes...
vpColVector Xest
static const vpColor green
Definition: vpColor.h:166
This tracker is meant to track a blob (connex pixels with same gray level) on a vpImage.
Definition: vpDot2.h:124
void track(const vpImage< unsigned char > &I)
Definition: vpDot2.cpp:461
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:2233
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
vpImagePoint getCog() const
Definition: vpDot2.h:160
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:404
void initStandard(double gain_at_zero, double gain_at_infinity, double slope_at_zero)
Initialize the velocity controller.
Definition: vpRobot.h:68
double get_v0() const
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayOpenCV allows to display image using the opencv library.
virtual void displayCross(const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)=0
Generic class defining intrinsic camera parameters.
static std::string getUserName()
Definition: vpIoTools.cpp:161
void initFromConstant(double c)
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:141
void buildFrom(const double x, const double y, const double Z)
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:93
vpRobot::vpRobotStateType setRobotState(vpRobot::vpRobotStateType newState)
Implementation of column vector and the associated operations.
Definition: vpColVector.h:72
void getVelocity(const vpRobot::vpControlFrameType frame, vpColVector &velocity)
Control of Irisa's cylindrical robot named Afma4.
Definition: vpRobotAfma4.h:177
void initTracking(const vpImage< unsigned char > &I, unsigned int size=0)
Definition: vpDot2.cpp:262
This class provides an implementation of some specific linear Kalman filters.
unsigned int getHeight() const
Definition: vpImage.h:152
Class for firewire ieee1394 video devices using libdc1394-2.x api.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
static void create(vpFeaturePoint &s, const vpCameraParameters &cam, const vpDot &d)
static void display(const vpServo &s, const vpCameraParameters &cam, const vpImage< unsigned char > &I, vpColor currentColor=vpColor::green, vpColor desiredColor=vpColor::red, unsigned int thickness=1)
void setGraphics(const bool activate)
Definition: vpDot2.h:309
static const vpColor blue
Definition: vpColor.h:169
void resize(const unsigned int i, const bool flagNullify=true)
Definition: vpColVector.h:217