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