Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
servoSimuSphere.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Description:
32  * Demonstration of the wireframe simulator with a simple visual servoing
33  *
34  * Authors:
35  * Nicolas Melchior
36  *
37  *****************************************************************************/
38 
45 #include <cmath> // std::fabs
46 #include <limits> // numeric_limits
47 #include <stdlib.h>
48 
49 #include <visp3/core/vpCameraParameters.h>
50 #include <visp3/core/vpHomogeneousMatrix.h>
51 #include <visp3/core/vpImage.h>
52 #include <visp3/core/vpIoTools.h>
53 #include <visp3/core/vpMath.h>
54 #include <visp3/core/vpSphere.h>
55 #include <visp3/core/vpTime.h>
56 #include <visp3/core/vpVelocityTwistMatrix.h>
57 #include <visp3/gui/vpDisplayD3D.h>
58 #include <visp3/gui/vpDisplayGDI.h>
59 #include <visp3/gui/vpDisplayGTK.h>
60 #include <visp3/gui/vpDisplayOpenCV.h>
61 #include <visp3/gui/vpDisplayX.h>
62 #include <visp3/io/vpImageIo.h>
63 #include <visp3/io/vpParseArgv.h>
64 #include <visp3/robot/vpSimulatorCamera.h>
65 #include <visp3/robot/vpWireFrameSimulator.h>
66 #include <visp3/visual_features/vpFeatureBuilder.h>
67 #include <visp3/visual_features/vpGenericFeature.h>
68 #include <visp3/vs/vpServo.h>
69 
70 #define GETOPTARGS "dh"
71 
72 #ifdef VISP_HAVE_DISPLAY
73 
74 void usage(const char *name, const char *badparam);
75 bool getOptions(int argc, const char **argv, bool &display);
76 void computeVisualFeatures(const vpSphere &sphere, vpGenericFeature &s);
77 void computeInteractionMatrix(const vpGenericFeature &s, const vpSphere &sphere, vpMatrix &L);
78 
87 void usage(const char *name, const char *badparam)
88 {
89  fprintf(stdout, "\n\
90 Demonstration of the wireframe simulator with a simple visual servoing.\n\
91  \n\
92 The visual servoing consists in bringing the camera at a desired position from the object.\n\
93  \n\
94 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\
95  \n\
96 SYNOPSIS\n\
97  %s [-d] [-h]\n", name);
98 
99  fprintf(stdout, "\n\
100 OPTIONS: Default\n\
101  -d \n\
102  Turn off the display.\n\
103  \n\
104  -h\n\
105  Print the help.\n");
106 
107  if (badparam)
108  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
109 }
110 
122 bool getOptions(int argc, const char **argv, bool &display)
123 {
124  const char *optarg_;
125  int c;
126  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
127 
128  switch (c) {
129  case 'd':
130  display = false;
131  break;
132  case 'h':
133  usage(argv[0], NULL);
134  return false;
135  break;
136 
137  default:
138  usage(argv[0], optarg_);
139  return false;
140  break;
141  }
142  }
143 
144  if ((c == 1) || (c == -1)) {
145  // standalone param or error
146  usage(argv[0], NULL);
147  std::cerr << "ERROR: " << std::endl;
148  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
149  return false;
150  }
151 
152  return true;
153 }
154 
155 /*
156  Computes the virtual visual features corresponding to the sphere and stores
157  it in the generic feature.
158 
159  The visual feature vector is computed thanks to the following formula : s =
160  {sx, sy, sz} sx = gx*h2/(sqrt(h2+1) sx = gy*h2/(sqrt(h2+1) sz = sqrt(h2+1)
161 
162  with gx and gy the center of gravity of the ellipse,
163  with h2 = (gx²+gy²)/(4*n20*gy²+4*n02*gx²-8n11gxgy)
164  with n20,n02,n11 the second order moments of the sphere
165 */
166 void computeVisualFeatures(const vpSphere &sphere, vpGenericFeature &s)
167 {
168  double gx = sphere.get_x();
169  double gy = sphere.get_y();
170  double m02 = sphere.get_mu02();
171  double m20 = sphere.get_mu20();
172  double m11 = sphere.get_mu11();
173  double h2;
174  // if (gx != 0 || gy != 0)
175  if (std::fabs(gx) > std::numeric_limits<double>::epsilon() || std::fabs(gy) > std::numeric_limits<double>::epsilon())
176  h2 = (vpMath::sqr(gx) + vpMath::sqr(gy)) /
177  (4 * m20 * vpMath::sqr(gy) + 4 * m02 * vpMath::sqr(gx) - 8 * m11 * gx * gy);
178  else
179  h2 = 1 / (4 * m20);
180 
181  double sx = gx * h2 / (sqrt(h2 + 1));
182  double sy = gy * h2 / (sqrt(h2 + 1));
183  double sz = sqrt(h2 + 1); //(h2-(vpMath::sqr(sx)+vpMath::sqr(sy)-1))/(2*sqrt(h2));
184 
185  s.set_s(sx, sy, sz);
186 }
187 
188 /*
189  Computes the interaction matrix such as L = [-1/R*I3 [s]x]
190 
191  with R the radius of the sphere
192  with I3 the 3x3 identity matrix
193  with [s]x the skew matrix related to s
194 */
195 void computeInteractionMatrix(const vpGenericFeature &s, const vpSphere &sphere, vpMatrix &L)
196 {
197  L = 0;
198  L[0][0] = -1 / sphere.getR();
199  L[1][1] = -1 / sphere.getR();
200  L[2][2] = -1 / sphere.getR();
201 
202  double s0, s1, s2;
203  s.get_s(s0, s1, s2);
204 
205  vpTranslationVector c(s0, s1, s2);
206  vpMatrix sk;
207  sk = c.skew();
208 
209  for (unsigned int i = 0; i < 3; i++)
210  for (unsigned int j = 0; j < 3; j++)
211  L[i][j + 3] = sk[i][j];
212 }
213 
214 int 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  // Display size is automatically defined by the image (I) size
242  display[0].init(Iint, 100, 100, "The internal view");
243  display[1].init(Iext1, 100, 100, "The first external view");
244  display[2].init(Iext2, 100, 100, "The second external view");
245  vpDisplay::setWindowPosition(Iint, 0, 0);
246  vpDisplay::setWindowPosition(Iext1, 700, 0);
247  vpDisplay::setWindowPosition(Iext2, 0, 550);
248  vpDisplay::display(Iint);
249  vpDisplay::flush(Iint);
250  vpDisplay::display(Iext1);
251  vpDisplay::flush(Iext1);
252  vpDisplay::display(Iext2);
253  vpDisplay::flush(Iext2);
254  }
255 
256  vpServo task;
257  vpSimulatorCamera robot;
258  float sampling_time = 0.040f; // Sampling period in second
259  robot.setSamplingTime(sampling_time);
260 
261  // Since the task gain lambda is very high, we need to increase default
262  // 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
274  wMc = wMo * cMo.inverse();
275 
276  robot.setPosition(wMc);
277 
278  // The sphere
279  vpSphere sphere(0, 0, 0, 0.15);
280 
281  // Projection of the sphere
282  sphere.track(cMo);
283 
284  // Set the current visual feature
285  vpGenericFeature s(3);
286  computeVisualFeatures(sphere, s);
287 
288  // Projection of the points
289  sphere.track(cdMo);
290 
291  vpGenericFeature sd(3);
292  computeVisualFeatures(sphere, sd);
293 
294  vpMatrix L(3, 6);
295  computeInteractionMatrix(sd, sphere, L);
296  sd.setInteractionMatrix(L);
297 
300 
302  vpVelocityTwistMatrix cVe(cMe);
303  task.set_cVe(cVe);
304 
305  vpMatrix eJe;
306  robot.get_eJe(eJe);
307  task.set_eJe(eJe);
308 
309  task.addFeature(s, sd);
310 
311  task.setLambda(7);
312 
314 
315  // Set the scene
317 
318  // Initialize simulator frames
319  sim.set_fMo(wMo); // Position of the object in the world reference frame
320  sim.setCameraPositionRelObj(cMo); // Initial position of the object in the camera frame
321  sim.setDesiredCameraPosition(cdMo); // Desired position of the object in the camera frame
322 
323  // Set the External camera position
324  vpHomogeneousMatrix camMf(0.0, 0, 3.5, vpMath::rad(0), vpMath::rad(30), 0);
325  sim.setExternalCameraPosition(camMf);
326 
327  // Computes the position of a camera which is fixed in the object frame
328  vpHomogeneousMatrix camoMf(0, 0.0, 2.5, 0, vpMath::rad(140), 0);
329  camoMf = camoMf * (sim.get_fMo().inverse());
330 
331  // Set the parameters of the cameras (internal and external)
332  vpCameraParameters camera(1000, 1000, 320, 240);
333  sim.setInternalCameraParameters(camera);
334  sim.setExternalCameraParameters(camera);
335 
336  int stop = 10;
337 
338  if (opt_display) {
339  stop = 1000;
340  // Get the internal and external views
341  sim.getInternalImage(Iint);
342  sim.getExternalImage(Iext1);
343  sim.getExternalImage(Iext2, camoMf);
344 
345  // Display the object frame (current and desired position)
346  vpDisplay::displayFrame(Iint, cMo, camera, 0.2, vpColor::none);
347  vpDisplay::displayFrame(Iint, cdMo, camera, 0.2, vpColor::none);
348 
349  // Display the object frame the world reference frame and the camera
350  // frame
351  vpDisplay::displayFrame(Iext1, camMf * sim.get_fMo() * cMo.inverse(), camera, 0.2, vpColor::none);
352  vpDisplay::displayFrame(Iext1, camMf * sim.get_fMo(), camera, 0.2, vpColor::none);
353  vpDisplay::displayFrame(Iext1, camMf, camera, 0.2, vpColor::none);
354 
355  // Display the world reference frame and the object frame
356  vpDisplay::displayFrame(Iext2, camoMf, camera, 0.2, vpColor::none);
357  vpDisplay::displayFrame(Iext2, camoMf * sim.get_fMo(), camera, 0.05, vpColor::none);
358 
359  vpDisplay::flush(Iint);
360  vpDisplay::flush(Iext1);
361  vpDisplay::flush(Iext2);
362 
363  std::cout << "Click on a display" << std::endl;
364  while (!vpDisplay::getClick(Iint, false) && !vpDisplay::getClick(Iext1, false) &&
365  !vpDisplay::getClick(Iext2, false)) {
366  };
367  }
368 
369  // Print the task
370  task.print();
371 
372  int iter = 0;
373  vpColVector v;
374 
375  while (iter++ < stop) {
376  if (opt_display) {
377  vpDisplay::display(Iint);
378  vpDisplay::display(Iext1);
379  vpDisplay::display(Iext2);
380  }
381 
382  double t = vpTime::measureTimeMs();
383 
384  robot.get_eJe(eJe);
385  task.set_eJe(eJe);
386 
387  wMc = robot.getPosition();
388  cMo = wMc.inverse() * wMo;
389 
390  sphere.track(cMo);
391 
392  // Set the current visual feature
393  computeVisualFeatures(sphere, s);
394 
395  v = task.computeControlLaw();
397  sim.setCameraPositionRelObj(cMo);
398 
399  // Compute the position of the external view which is fixed in the
400  // 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  // Get the internal and external views
406  sim.getInternalImage(Iint);
407  sim.getExternalImage(Iext1);
408  sim.getExternalImage(Iext2, camoMf);
409 
410  // Display the object frame (current and desired position)
411  vpDisplay::displayFrame(Iint, cMo, camera, 0.2, vpColor::none);
412  vpDisplay::displayFrame(Iint, cdMo, camera, 0.2, vpColor::none);
413 
414  // Display the camera frame, the object frame the world reference
415  // frame
416  vpDisplay::displayFrame(Iext1, sim.getExternalCameraPosition() * sim.get_fMo() * cMo.inverse(), camera, 0.2,
417  vpColor::none);
418  vpDisplay::displayFrame(Iext1, sim.getExternalCameraPosition() * sim.get_fMo(), camera, 0.2, vpColor::none);
420 
421  // Display the world reference frame and the object frame
422  vpDisplay::displayFrame(Iext2, camoMf, camera, 0.2, vpColor::none);
423  vpDisplay::displayFrame(Iext2, camoMf * sim.get_fMo(), camera, 0.05, vpColor::none);
424 
425  vpDisplay::flush(Iint);
426  vpDisplay::flush(Iext1);
427  vpDisplay::flush(Iext2);
428  }
429 
430  vpTime::wait(t, sampling_time * 1000); // Wait 40 ms
431 
432  std::cout << "|| s - s* || = " << (task.getError()).sumSquare() << std::endl;
433  }
434 
435  task.print();
436  task.kill();
437  return EXIT_SUCCESS;
438  } catch (const vpException &e) {
439  std::cout << "Catch an exception: " << e << std::endl;
440  return EXIT_FAILURE;
441  }
442 }
443 #else
444 int main()
445 {
446  std::cout << "You do not have X11, or GDI (Graphical Device Interface), or GTK functionalities to display images..." << std::endl;
447  std::cout << "Tip if you are on a unix-like system:" << std::endl;
448  std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
449  std::cout << "Tip if you are on a windows-like system:" << std::endl;
450  std::cout << "- Install GDI, configure again ViSP using cmake and build again this example" << std::endl;
451  return EXIT_SUCCESS;
452 }
453 #endif
void setPosition(const vpHomogeneousMatrix &wMc)
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:164
VISP_EXPORT int wait(double t0, double t)
Definition: vpTime.cpp:173
double getR() const
Definition: vpSphere.h:84
void set_s(const vpColVector &s)
set the value of all the features.
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
void setVelocity(const vpRobot::vpControlFrameType frame, const vpColVector &vel)
Implementation of an homogeneous matrix and operations on such kind of matrices.
Class that defines the simplest robot: a free flying camera.
vpHomogeneousMatrix get_fMo() const
void addFeature(vpBasicFeature &s, vpBasicFeature &s_star, unsigned int select=vpBasicFeature::FEATURE_ALL)
Definition: vpServo.cpp:497
void set_fMo(const vpHomogeneousMatrix &fMo_)
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
void get_s(vpColVector &s) const
get the value of all the features.
void set_eJe(const vpMatrix &eJe_)
Definition: vpServo.h:508
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:150
static const vpColor none
Definition: vpColor.h:191
error that can be emited by ViSP classes.
Definition: vpException.h:71
void track(const vpHomogeneousMatrix &cMo)
vpHomogeneousMatrix inverse() const
void setExternalCameraPosition(const vpHomogeneousMatrix &cam_Mf)
Class that defines what is a sphere.
Definition: vpSphere.h:60
double get_mu11() const
Definition: vpSphere.h:77
vpHomogeneousMatrix getPosition() const
void setDesiredCameraPosition(const vpHomogeneousMatrix &cdMo_)
static void flush(const vpImage< unsigned char > &I)
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:126
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
void setMaxRotationVelocity(double maxVr)
Definition: vpRobot.cpp:260
virtual void setSamplingTime(const double &delta_t)
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed...
Definition: vpDisplayD3D.h:106
double get_x() const
Definition: vpSphere.h:74
void kill()
Definition: vpServo.cpp:192
vpColVector computeControlLaw()
Definition: vpServo.cpp:935
static double sqr(double x)
Definition: vpMath.h:114
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Generic class defining intrinsic camera parameters.
void setLambda(double c)
Definition: vpServo.h:406
void initScene(const vpSceneObject &obj, const vpSceneDesiredObject &desiredObject)
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:137
void getExternalImage(vpImage< unsigned char > &I)
Implementation of a wire frame simulator. Compared to the vpSimulator class, it does not require thir...
void setInteractionMatrixType(const vpServoIteractionMatrixType &interactionMatrixType, const vpServoInversionType &interactionMatrixInversion=PSEUDO_INVERSE)
Definition: vpServo.cpp:574
static double rad(double deg)
Definition: vpMath.h:108
void setExternalCameraParameters(const vpCameraParameters &cam)
double get_mu20() const
Definition: vpSphere.h:76
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
void setCameraPositionRelObj(const vpHomogeneousMatrix &cMo_)
void getInternalImage(vpImage< unsigned char > &I)
double get_y() const
Definition: vpSphere.h:75
static void setWindowPosition(const vpImage< unsigned char > &I, int winx, int winy)
Implementation of column vector and the associated operations.
Definition: vpColVector.h:130
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0))
void set_cVe(const vpVelocityTwistMatrix &cVe_)
Definition: vpServo.h:450
void setInternalCameraParameters(const vpCameraParameters &cam)
void print(const vpServo::vpServoPrintType display_level=ALL, std::ostream &os=std::cout)
Definition: vpServo.cpp:313
vpColVector getError() const
Definition: vpServo.h:282
Class that enables to define a feature or a set of features which are not implemented in ViSP as a sp...
void get_eJe(vpMatrix &eJe)
double get_mu02() const
Definition: vpSphere.h:78
void setServo(const vpServoType &servo_type)
Definition: vpServo.cpp:223
void setMaxTranslationVelocity(double maxVt)
Definition: vpRobot.cpp:239
Class that consider the case of a translation vector.
vpHomogeneousMatrix getExternalCameraPosition() const