ViSP  2.9.0
servoSimuSphere.cpp
1 /****************************************************************************
2  *
3  * $Id: servoSimuSphere.cpp 4658 2014-02-09 09:50:14Z 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  * Demonstration of the wireframe simulator with a simple visual servoing
36  *
37  * Authors:
38  * Nicolas Melchior
39  *
40  *****************************************************************************/
41 
48 #include <stdlib.h>
49 #include <cmath> // std::fabs
50 #include <limits> // numeric_limits
51 
52 #include <visp/vpCameraParameters.h>
53 #include <visp/vpDisplayOpenCV.h>
54 #include <visp/vpDisplayX.h>
55 #include <visp/vpDisplayGTK.h>
56 #include <visp/vpDisplayGDI.h>
57 #include <visp/vpDisplayD3D.h>
58 #include <visp/vpFeatureBuilder.h>
59 #include <visp/vpGenericFeature.h>
60 #include <visp/vpHomogeneousMatrix.h>
61 #include <visp/vpImage.h>
62 #include <visp/vpImageIo.h>
63 #include <visp/vpIoTools.h>
64 #include <visp/vpMath.h>
65 #include <visp/vpParseArgv.h>
66 #include <visp/vpRobotCamera.h>
67 #include <visp/vpServo.h>
68 #include <visp/vpSphere.h>
69 #include <visp/vpTime.h>
70 #include <visp/vpVelocityTwistMatrix.h>
71 #include <visp/vpWireFrameSimulator.h>
72 
73 #define GETOPTARGS "dh"
74 
75 #ifdef VISP_HAVE_DISPLAY
76 
77 void usage(const char *name, const char *badparam);
78 bool getOptions(int argc, const char **argv, bool &display);
79 void computeVisualFeatures(const vpSphere &sphere, vpGenericFeature &s);
80 void computeInteractionMatrix(const vpGenericFeature &s,const vpSphere &sphere, vpMatrix &L);
81 
90 void usage(const char *name, const char *badparam)
91 {
92  fprintf(stdout, "\n\
93 Demonstration of the wireframe simulator with a simple visual servoing.\n\
94  \n\
95 The visual servoing consists in bringing the camera at a desired position from the object.\n\
96  \n\
97 The visual features used to compute the pose of the camera and thus the control law are special moments computed with the sphere's parameters.\n\
98  \n\
99 SYNOPSIS\n\
100  %s [-d] [-h]\n", name);
101 
102  fprintf(stdout, "\n\
103 OPTIONS: Default\n\
104  -d \n\
105  Turn off the display.\n\
106  \n\
107  -h\n\
108  Print the help.\n");
109 
110  if (badparam)
111  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
112 }
113 
125 bool getOptions(int argc, const char **argv, bool &display)
126 {
127  const char *optarg_;
128  int c;
129  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
130 
131  switch (c) {
132  case 'd': display = false; break;
133  case 'h': usage(argv[0], NULL); return false; break;
134 
135  default:
136  usage(argv[0], optarg_);
137  return false; break;
138  }
139  }
140 
141  if ((c == 1) || (c == -1)) {
142  // standalone param or error
143  usage(argv[0], NULL);
144  std::cerr << "ERROR: " << std::endl;
145  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
146  return false;
147  }
148 
149  return true;
150 }
151 
152 
153 /*
154  Computes the virtual visual features corresponding to the sphere and stores it in the generic feature.
155 
156  The visual feature vector is computed thanks to the following formula : s = {sx, sy, sz}
157  sx = gx*h2/(sqrt(h2+1)
158  sx = gy*h2/(sqrt(h2+1)
159  sz = sqrt(h2+1)
160 
161  with gx and gy the center of gravity of the ellipse,
162  with h2 = (gx²+gy²)/(4*n20*gy²+4*n02*gx²-8n11gxgy)
163  with n20,n02,n11 the second order moments of the sphere
164 */
165 void computeVisualFeatures(const vpSphere &sphere, vpGenericFeature &s)
166 {
167  double gx = sphere.get_x();
168  double gy = sphere.get_y();
169  double m02 = sphere.get_mu02();
170  double m20 = sphere.get_mu20();
171  double m11 = sphere.get_mu11();
172  double h2;
173  //if (gx != 0 || gy != 0)
174  if (std::fabs(gx) > std::numeric_limits<double>::epsilon() || std::fabs(gy) > std::numeric_limits<double>::epsilon())
175  h2 = (vpMath::sqr(gx)+vpMath::sqr(gy))/(4*m20*vpMath::sqr(gy)+4*m02*vpMath::sqr(gx)-8*m11*gx*gy);
176  else
177  h2 = 1/(4*m20);
178 
179  double sx = gx*h2/(sqrt(h2+1));
180  double sy = gy*h2/(sqrt(h2+1));
181  double sz = sqrt(h2+1); //(h2-(vpMath::sqr(sx)+vpMath::sqr(sy)-1))/(2*sqrt(h2));
182 
183  s.set_s(sx,sy,sz);
184 }
185 
186 /*
187  Computes the interaction matrix such as L = [-1/R*I3 [s]x]
188 
189  with R the radius of the sphere
190  with I3 the 3x3 identity matrix
191  with [s]x the skew matrix related to s
192 */
193 void computeInteractionMatrix(const vpGenericFeature &s,const vpSphere &sphere, vpMatrix &L)
194 {
195  L = 0;
196  L[0][0] = -1/sphere.getR();
197  L[1][1] = -1/sphere.getR();
198  L[2][2] = -1/sphere.getR();
199 
200  double s0,s1,s2;
201  s.get_s(s0,s1,s2);
202 
203  vpTranslationVector c(s0,s1,s2);
204  vpMatrix sk;
205  sk = c.skew();
206 
207  for(unsigned int i = 0; i < 3; i++)
208  for(unsigned int j = 0; j < 3; j++)
209  L[i][j+3] = sk[i][j];
210 }
211 
212 
213 int
214 main(int argc, const char ** argv)
215 {
216  try {
217  bool opt_display = true;
218 
219  // Read the command line options
220  if (getOptions(argc, argv, opt_display) == false) {
221  exit (-1);
222  }
223 
224  vpImage<vpRGBa> Iint(480,640,255);
225  vpImage<vpRGBa> Iext1(480,640,255);
226  vpImage<vpRGBa> Iext2(480,640,255);
227 
228 #if defined VISP_HAVE_X11
229  vpDisplayX display[3];
230 #elif defined VISP_HAVE_OPENCV
231  vpDisplayOpenCV display[3];
232 #elif defined VISP_HAVE_GDI
233  vpDisplayGDI display[3];
234 #elif defined VISP_HAVE_D3D9
235  vpDisplayD3D display[3];
236 #elif defined VISP_HAVE_GTK
237  vpDisplayGTK display[3];
238 #endif
239 
240  if (opt_display)
241  {
242  // Display size is automatically defined by the image (I) size
243  display[0].init(Iint, 100, 100,"The internal view") ;
244  display[1].init(Iext1, 100, 100,"The first external view") ;
245  display[2].init(Iext2, 100, 100,"The second external view") ;
246  vpDisplay::setWindowPosition (Iint, 0, 0);
247  vpDisplay::setWindowPosition (Iext1, 700, 0);
248  vpDisplay::setWindowPosition (Iext2, 0, 550);
249  vpDisplay::display(Iint);
250  vpDisplay::flush(Iint);
251  vpDisplay::display(Iext1);
252  vpDisplay::flush(Iext1);
253  vpDisplay::display(Iext2);
254  vpDisplay::flush(Iext2);
255  }
256 
257  vpServo task;
258  vpRobotCamera robot ;
259  float sampling_time = 0.040f; // Sampling period in second
260  robot.setSamplingTime(sampling_time);
261 
262  // Since the task gain lambda is very high, we need to increase default max velocities
263  robot.setMaxTranslationVelocity(10);
265 
266  // Set initial position of the object in the camera frame
267  vpHomogeneousMatrix cMo(0,0.1,2.0,vpMath::rad(35),vpMath::rad(25),0);
268  // Set desired position of the object in the camera frame
269  vpHomogeneousMatrix cdMo(0.0,0.0,0.8,vpMath::rad(0),vpMath::rad(0),vpMath::rad(0));
270  // Set initial position of the object in the world frame
271  vpHomogeneousMatrix wMo(0.0,0.0,0,0,0,0);
272  // Position of the camera in the world frame
273  vpHomogeneousMatrix wMc, cMw;
274  wMc = wMo * cMo.inverse();
275  cMw = wMc.inverse();
276 
277  robot.setPosition( cMw );
278 
279  //The sphere
280  vpSphere sphere(0,0,0,0.15);
281 
282  // Projection of the sphere
283  sphere.track(cMo);
284 
285  //Set the current visual feature
286  vpGenericFeature s(3);
287  computeVisualFeatures(sphere, s);
288 
289  // Projection of the points
290  sphere.track(cdMo);
291 
292  vpGenericFeature sd(3);
293  computeVisualFeatures(sphere, sd);
294 
295  vpMatrix L(3,6);
296  computeInteractionMatrix(sd,sphere,L);
297  sd.setInteractionMatrix(L);
298 
301 
303  vpVelocityTwistMatrix cVe(cMe);
304  task.set_cVe(cVe);
305 
306  vpMatrix eJe;
307  robot.get_eJe(eJe);
308  task.set_eJe(eJe);
309 
310  task.addFeature(s,sd) ;
311 
312  task.setLambda(7);
313 
315 
316  // Set the scene
318 
319  // Initialize simulator frames
320  sim.set_fMo( wMo ); // Position of the object in the world reference frame
321  sim.setCameraPositionRelObj(cMo) ; // initial position of the camera
322  sim.setDesiredCameraPosition(cdMo); // desired position of the camera
323 
324  // Set the External camera position
325  vpHomogeneousMatrix camMf(0.0,0,3.5,vpMath::rad(0),vpMath::rad(30),0);
326  sim.setExternalCameraPosition(camMf);
327 
328  // Computes the position of a camera which is fixed in the object frame
329  vpHomogeneousMatrix camoMf(0,0.0,2.5,0,vpMath::rad(140),0);
330  camoMf = camoMf*(sim.get_fMo().inverse());
331 
332  // Set the parameters of the cameras (internal and external)
333  vpCameraParameters camera(1000,1000,320,240);
334  sim.setInternalCameraParameters(camera);
335  sim.setExternalCameraParameters(camera);
336 
337  int stop = 10;
338 
339  if (opt_display)
340  {
341  stop = 1000;
342  //Get the internal and external views
343  sim.getInternalImage(Iint);
344  sim.getExternalImage(Iext1);
345  sim.getExternalImage(Iext2,camoMf);
346 
347  //Display the object frame (current and desired position)
348  vpDisplay::displayFrame(Iint,cMo,camera,0.2,vpColor::none);
349  vpDisplay::displayFrame(Iint,cdMo,camera,0.2,vpColor::none);
350 
351  //Display the object frame the world reference frame and the camera frame
352  vpDisplay::displayFrame(Iext1,camMf*sim.get_fMo()*cMo.inverse(),camera,0.2,vpColor::none);
353  vpDisplay::displayFrame(Iext1,camMf*sim.get_fMo(),camera,0.2,vpColor::none);
354  vpDisplay::displayFrame(Iext1,camMf,camera,0.2,vpColor::none);
355 
356  //Display the world reference frame and the object frame
357  vpDisplay::displayFrame(Iext2,camoMf,camera,0.2,vpColor::none);
358  vpDisplay::displayFrame(Iext2,camoMf*sim.get_fMo(),camera,0.05,vpColor::none);
359 
360  vpDisplay::flush(Iint);
361  vpDisplay::flush(Iext1);
362  vpDisplay::flush(Iext2);
363 
364  std::cout << "Click on a display" << std::endl;
365  while (!vpDisplay::getClick(Iint,false) && !vpDisplay::getClick(Iext1,false) && !vpDisplay::getClick(Iext2,false)){};
366  }
367 
368  //Print the task
369  task.print() ;
370 
371  int iter = 0;
372  vpColVector v ;
373 
374  while(iter++ < stop)
375  {
376  if (opt_display)
377  {
378  vpDisplay::display(Iint) ;
379  vpDisplay::display(Iext1) ;
380  vpDisplay::display(Iext2) ;
381  }
382 
383  double t = vpTime::measureTimeMs();
384 
385  robot.get_eJe(eJe) ;
386  task.set_eJe(eJe) ;
387 
388  robot.getPosition(cMw) ;
389  cMo = cMw * wMo;
390 
391  sphere.track(cMo);
392 
393  //Set the current visual feature
394  computeVisualFeatures(sphere, s);
395 
396  v = task.computeControlLaw() ;
398  sim.setCameraPositionRelObj(cMo);
399 
400  //Compute the position of the external view which is fixed in the object frame
401  camoMf.buildFrom(0,0.0,2.5,0,vpMath::rad(150),0);
402  camoMf = camoMf*(sim.get_fMo().inverse());
403 
404  if (opt_display)
405  {
406  //Get the internal and external views
407  sim.getInternalImage(Iint);
408  sim.getExternalImage(Iext1);
409  sim.getExternalImage(Iext2,camoMf);
410 
411  //Display the object frame (current and desired position)
412  vpDisplay::displayFrame(Iint,cMo,camera,0.2,vpColor::none);
413  vpDisplay::displayFrame(Iint,cdMo,camera,0.2,vpColor::none);
414 
415  //Display the camera frame, the object frame the world reference frame
419 
420  //Display the world reference frame and the object frame
421  vpDisplay::displayFrame(Iext2,camoMf,camera,0.2,vpColor::none);
422  vpDisplay::displayFrame(Iext2,camoMf*sim.get_fMo(),camera,0.05,vpColor::none);
423 
424  vpDisplay::flush(Iint);
425  vpDisplay::flush(Iext1);
426  vpDisplay::flush(Iext2);
427  }
428 
429  vpTime::wait(t, sampling_time * 1000); // Wait 40 ms
430 
431  std::cout << "|| s - s* || = " << ( task.getError() ).sumSquare() <<std::endl ;
432  }
433 
434  task.print() ;
435  task.kill() ;
436  return 0;
437  }
438  catch(vpException e) {
439  std::cout << "Catch an exception: " << e << std::endl;
440  return 1;
441  }
442 }
443 #else
444 int
445 main()
446 {
447  vpERROR_TRACE("You do not have X11, OpenCV, GDI, D3D9 or GTK display functionalities...");
448 }
449 
450 #endif
The object displayed at the desired position is the same than the scene object defined in vpSceneObje...
double get_mu02() const
Definition: vpSphere.h:87
Definition of the vpMatrix class.
Definition: vpMatrix.h:98
double getR() const
Definition: vpSphere.h:93
void set_s(const vpColVector &s)
set the value of all the features.
double get_x() const
Definition: vpSphere.h:83
void setMaxTranslationVelocity(const double maxVt)
Definition: vpRobot.cpp:227
The class provides a data structure for the homogeneous matrices as well as a set of operations on th...
#define vpERROR_TRACE
Definition: vpDebug.h:395
void setPosition(const vpHomogeneousMatrix &cMw)
void set_fMo(const vpHomogeneousMatrix &fMo_)
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:132
void set_eJe(const vpMatrix &eJe_)
Definition: vpServo.h:439
Define the X11 console to display images.
Definition: vpDisplayX.h:152
void addFeature(vpBasicFeature &s, vpBasicFeature &s_star, const unsigned int select=vpBasicFeature::FEATURE_ALL)
Definition: vpServo.cpp:449
double get_mu11() const
Definition: vpSphere.h:86
static const vpColor none
Definition: vpColor.h:179
error that can be emited by ViSP classes.
Definition: vpException.h:76
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
void track(const vpHomogeneousMatrix &cMo)
void setExternalCameraPosition(const vpHomogeneousMatrix &cam_Mf)
static double measureTimeMs()
Definition: vpTime.cpp:86
Class that defines what is a sphere.
Definition: vpSphere.h:64
static int wait(double t0, double t)
Definition: vpTime.cpp:149
void setDesiredCameraPosition(const vpHomogeneousMatrix &cdMo_)
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1994
void skew(const vpTranslationVector &t, vpMatrix &M)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:79
void get_s(vpColVector &s) const
get the value of all the features.
double get_mu20() const
Definition: vpSphere.h:85
virtual void setSamplingTime(const double &delta_t)
Display for windows using Direct3D.
Definition: vpDisplayD3D.h:109
void kill()
Definition: vpServo.cpp:189
vpColVector getError() const
Definition: vpServo.h:257
vpHomogeneousMatrix get_fMo() const
vpColVector computeControlLaw()
Definition: vpServo.cpp:902
virtual void setWindowPosition(int winx, int winy)=0
static double sqr(double x)
Definition: vpMath.h:106
Class that defines the simplest robot: a free flying camera.
double get_y() const
Definition: vpSphere.h:84
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayOpenCV allows to display image using the opencv library.
Generic class defining intrinsic camera parameters.
void setLambda(double c)
Definition: vpServo.h:370
void initScene(const vpSceneObject &obj, const vpSceneDesiredObject &desiredObject)
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:145
Class that consider the particular case of twist transformation matrix that allows to transform a vel...
void getExternalImage(vpImage< unsigned char > &I)
Implementation of a wire frame simulator. Compared to the vpSimulator class, it does not require thir...
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color, unsigned int thickness=1)
Definition: vpDisplay.cpp:371
void setInteractionMatrixType(const vpServoIteractionMatrixType &interactionMatrixType, const vpServoInversionType &interactionMatrixInversion=PSEUDO_INVERSE)
Definition: vpServo.cpp:522
static double rad(double deg)
Definition: vpMath.h:100
void setExternalCameraParameters(const vpCameraParameters &cam)
void setCameraPositionRelObj(const vpHomogeneousMatrix &cMo_)
void setMaxRotationVelocity(const double maxVr)
Definition: vpRobot.cpp:251
void getInternalImage(vpImage< unsigned char > &I)
void getPosition(vpHomogeneousMatrix &cMw) const
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 get_eJe(vpMatrix &eJe)
void set_cVe(const vpVelocityTwistMatrix &cVe_)
Definition: vpServo.h:414
vpHomogeneousMatrix inverse() const
void setInternalCameraParameters(const vpCameraParameters &cam)
void print(const vpServo::vpServoPrintType display_level=ALL, std::ostream &os=std::cout)
Definition: vpServo.cpp:251
virtual bool getClick(bool blocking=true)=0
Class that enables to define a feature or a set of features which are not implemented in ViSP as a sp...
void setServo(const vpServoType &servo_type)
Definition: vpServo.cpp:220
void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &v)
Class that consider the case of a translation vector.
vpHomogeneousMatrix getExternalCameraPosition() const