Visual Servoing Platform  version 3.6.1 under development (2024-05-20)
servoMomentPoints.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 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  * Description:
32  * Example of visual servoing with moments using discrete points as object
33  * container
34  */
35 
41 #include <iostream>
42 #include <visp3/core/vpCameraParameters.h>
43 #include <visp3/core/vpConfig.h>
44 #include <visp3/core/vpDebug.h>
45 #include <visp3/core/vpHomogeneousMatrix.h>
46 #include <visp3/core/vpIoTools.h>
47 #include <visp3/core/vpMath.h>
48 #include <visp3/core/vpMomentCommon.h>
49 #include <visp3/core/vpMomentDatabase.h>
50 #include <visp3/core/vpMomentObject.h>
51 #include <visp3/core/vpPlane.h>
52 #include <visp3/gui/vpDisplayD3D.h>
53 #include <visp3/gui/vpDisplayGDI.h>
54 #include <visp3/gui/vpDisplayGTK.h>
55 #include <visp3/gui/vpDisplayOpenCV.h>
56 #include <visp3/gui/vpDisplayX.h>
57 #include <visp3/gui/vpPlot.h>
58 #include <visp3/robot/vpSimulatorAfma6.h>
59 #include <visp3/visual_features/vpFeatureBuilder.h>
60 #include <visp3/visual_features/vpFeatureMomentCommon.h>
61 #include <visp3/visual_features/vpFeaturePoint.h>
62 #include <visp3/vs/vpServo.h>
63 
64 #if !defined(VISP_HAVE_DISPLAY)
65 int main()
66 {
67  std::cout << "Can't run this example since no display capability is available." << std::endl;
68  std::cout << "You should install one of the following third-party library: X11, OpenCV, GDI, GTK." << std::endl;
69  return EXIT_SUCCESS;
70 }
71 #elif !defined(VISP_HAVE_THREADS)
72 int main()
73 {
74  std::cout << "Can't run this example since multi-threading capability is not available." << std::endl;
75  std::cout << "You should maybe enable cxx11 standard." << std::endl;
76  return EXIT_SUCCESS;
77 }
78 #else
79 
80 #ifndef DOXYGEN_SHOULD_SKIP_THIS
81 class servoMoment
82 {
83 public:
84  servoMoment()
85  : m_width(640), m_height(480), m_cMo(), m_cdMo(), m_robot(false), m_Iint(m_height, m_width, 255), m_task(), m_cam(),
86  m_error(0), m_imsim(), m_interaction_type(), m_src(6), m_dst(6), m_moments(nullptr), m_momentsDes(nullptr),
87  m_featureMoments(nullptr), m_featureMomentsDes(nullptr), m_displayInt(nullptr)
88  { }
89  ~servoMoment()
90  {
91 #ifdef VISP_HAVE_DISPLAY
92  if (m_displayInt) {
93  delete m_displayInt;
94  }
95 #endif
96  delete m_moments;
97  delete m_momentsDes;
98  delete m_featureMoments;
99  delete m_featureMomentsDes;
100  }
101 
102  // initialize scene in the interface
103  void initScene()
104  {
105  std::vector<vpPoint> src_pts;
106  std::vector<vpPoint> dst_pts;
107 
108  double x[8] = { 1, 3, 4, -1, -3, -2, -1, 1 };
109  double y[8] = { 0, 1, 4, 4, -2, -2, 1, 0 };
110  int nbpoints = 8;
111 
112  for (int i = 0; i < nbpoints; i++) {
113  vpPoint p(x[i] / 20, y[i] / 20, 0.0);
114  p.track(m_cMo);
115  src_pts.push_back(p);
116  }
117 
118  m_src.setType(vpMomentObject::DISCRETE);
119  m_src.fromVector(src_pts);
120  for (int i = 0; i < nbpoints; i++) {
121  vpPoint p(x[i] / 20, y[i] / 20, 0.0);
122  p.track(m_cdMo);
123  dst_pts.push_back(p);
124  }
125  m_dst.setType(vpMomentObject::DISCRETE);
126  m_dst.fromVector(dst_pts);
127  }
128 
129  // initialize the moment features
130  void initFeatures()
131  {
132  // A,B,C parameters of source and destination plane
133  double A;
134  double B;
135  double C;
136  double Ad;
137  double Bd;
138  double Cd;
139  // init main object: using moments up to order 6
140 
141  // Initializing values from regular plane (with ax+by+cz=d convention)
142  vpPlane pl;
143  pl.setABCD(0, 0, 1.0, 0);
144  pl.changeFrame(m_cMo);
145  planeToABC(pl, A, B, C);
146 
147  pl.setABCD(0, 0, 1.0, 0);
148  pl.changeFrame(m_cdMo);
149  planeToABC(pl, Ad, Bd, Cd);
150 
151  // extracting initial position (actually we only care about Zdst)
153  m_cdMo.extract(vec);
154 
157  // don't need to be specific, vpMomentCommon automatically loads
158  // Xg,Yg,An,Ci,Cj,Alpha moments
160  vpMomentCommon::getAlpha(m_dst), vec[2]);
161  m_momentsDes = new vpMomentCommon(vpMomentCommon::getSurface(m_dst), vpMomentCommon::getMu3(m_dst),
162  vpMomentCommon::getAlpha(m_dst), vec[2]);
163  // same thing with common features
164  m_featureMoments = new vpFeatureMomentCommon(*m_moments);
165  m_featureMomentsDes = new vpFeatureMomentCommon(*m_momentsDes);
166 
167  m_moments->updateAll(m_src);
168  m_momentsDes->updateAll(m_dst);
169 
170  m_featureMoments->updateAll(A, B, C);
171  m_featureMomentsDes->updateAll(Ad, Bd, Cd);
172 
173  // setup the interaction type
174  m_task.setInteractionMatrixType(m_interaction_type);
177  m_task.addFeature(m_featureMoments->getFeatureGravityNormalized(),
178  m_featureMomentsDes->getFeatureGravityNormalized());
179  m_task.addFeature(m_featureMoments->getFeatureAn(), m_featureMomentsDes->getFeatureAn());
180  m_task.addFeature(m_featureMoments->getFeatureCInvariant(), m_featureMomentsDes->getFeatureCInvariant(),
181  (1 << 3) | (1 << 5));
182  m_task.addFeature(m_featureMoments->getFeatureAlpha(), m_featureMomentsDes->getFeatureAlpha());
183 
184  m_task.setLambda(1.);
185  }
186 
187  // update moment objects and interface
188  void refreshScene(vpMomentObject &obj)
189  {
190  // double x[8] = { 0.05,0.15, 0.2,-0.05 ,-0.15,-0.1,-0.05,0.05};
191  // double y[8] = { 0,0.05, 0.2, 0.2, -0.1,-0.1, 0.05,0};
192  double x[8] = { 1, 3, 4, -1, -3, -2, -1, 1 };
193  double y[8] = { 0, 1, 4, 4, -2, -2, 1, 0 };
194  int nbpoints = 8;
195  std::vector<vpPoint> cur_pts;
196 
197  for (int i = 0; i < nbpoints; i++) {
198  vpPoint p(x[i] / 20, y[i] / 20, 0.0);
199  p.track(m_cMo);
200  cur_pts.push_back(p);
201  }
202  obj.fromVector(cur_pts);
203  }
204 
206  {
207  m_cMo = cMo; // init source matrix
208  m_cdMo = cdMo; // init destination matrix
209 
210  m_interaction_type = vpServo::CURRENT; // use interaction matrix for current position
211 
212 #ifdef VISP_HAVE_DISPLAY
213  // init the right display
214 #if defined(VISP_HAVE_X11)
215  m_displayInt = new vpDisplayX;
216 #elif defined(HAVE_OPENCV_HIGHGUI)
217  m_displayInt = new vpDisplayOpenCV;
218 #elif defined(VISP_HAVE_GDI)
219  m_displayInt = new vpDisplayGDI;
220 #elif defined(VISP_HAVE_D3D9)
221  m_displayInt = new vpDisplayD3D;
222 #elif defined(VISP_HAVE_GTK)
223  m_displayInt = new vpDisplayGTK;
224 #endif
225  m_displayInt->init(m_Iint, 50, 50, "Visual servoing with moments");
226 #endif
227 
228  paramRobot(); // set up robot parameters
229 
230  m_task.setServo(vpServo::EYEINHAND_CAMERA);
231  initScene(); // initialize graphical scene (for interface)
232  initFeatures(); // initialize moment features
233  }
234 
235  // launch the simulation
236  void execute(unsigned int nbIter)
237  {
238  vpPlot ViSP_plot;
239  init_visp_plot(ViSP_plot); // Initialize plot object
240 
241  // init main object: using moments up to order 6
242  vpMomentObject obj(6);
243  // setting object type (disrete, continuous[form polygon])
245 
246  std::cout << "Display task information " << std::endl;
247  m_task.print();
248 
249  vpDisplay::display(m_Iint);
250  m_robot.getInternalView(m_Iint);
251  vpDisplay::flush(m_Iint);
252  unsigned int iter = 0;
253 
255  while (iter++ < nbIter) {
256  vpColVector v;
257  // get the cMo
258  m_cMo = m_robot.get_cMo();
259  // setup the plane in A,B,C style
260  vpPlane pl;
261  double A, B, C;
262  pl.setABCD(0, 0, 1.0, 0);
263  pl.changeFrame(m_cMo);
264  planeToABC(pl, A, B, C);
265 
266  // track points, draw points and add refresh our object
267  refreshScene(obj);
268  // this is the most important thing to do: update our moments
269  m_moments->updateAll(obj);
270  // and update our features. Do it in that order. Features need to use the
271  // information computed by moments
272  m_featureMoments->updateAll(A, B, C);
273 
274  vpDisplay::display(m_Iint);
275  m_robot.getInternalView(m_Iint);
276 
277  if (iter == 1) {
278  vpDisplay::displayText(m_Iint, 20, 20, "Click to start servoing", vpColor::red);
279  vpDisplay::flush(m_Iint);
280  vpDisplay::getClick(m_Iint);
281  }
282  v = m_task.computeControlLaw();
283 
284  // pilot robot using position control. The displacement is t*v with t=10ms
285  // step robot.setPosition(vpRobot::CAMERA_FRAME,0.01*v);
286  m_robot.setVelocity(vpRobot::CAMERA_FRAME, v);
287 
288  ViSP_plot.plot(0, iter, v);
289  ViSP_plot.plot(1, iter, vpPoseVector(m_cMo)); // Plot the velocities
290  ViSP_plot.plot(2, iter, m_task.getError()); // cMo as translations and theta_u
291 
292  m_error = (m_task.getError()).sumSquare();
293 
294  vpDisplay::displayText(m_Iint, 20, 20, "Click to stop visual servo...", vpColor::red);
295  if (vpDisplay::getClick(m_Iint, false)) {
296  break;
297  }
298  vpDisplay::flush(m_Iint);
299  }
300 
301  vpDisplay::display(m_Iint);
302  m_robot.getInternalView(m_Iint);
303  vpDisplay::displayText(m_Iint, 20, 20, "Click to quit...", vpColor::red);
304  vpDisplay::flush(m_Iint);
305  vpDisplay::getClick(m_Iint);
306  }
307 
308  void removeJointLimits(vpSimulatorAfma6 &robot)
309  {
310  vpColVector limMin(6);
311  vpColVector limMax(6);
312  limMin[0] = vpMath::rad(-3600);
313  limMin[1] = vpMath::rad(-3600);
314  limMin[2] = vpMath::rad(-3600);
315  limMin[3] = vpMath::rad(-3600);
316  limMin[4] = vpMath::rad(-3600);
317  limMin[5] = vpMath::rad(-3600);
318 
319  limMax[0] = vpMath::rad(3600);
320  limMax[1] = vpMath::rad(3600);
321  limMax[2] = vpMath::rad(3600);
322  limMax[3] = vpMath::rad(3600);
323  limMax[4] = vpMath::rad(3600);
324  limMax[5] = vpMath::rad(3600);
325 
326  robot.setJointLimit(limMin, limMax);
327  robot.setMaxRotationVelocity(99999);
328  robot.setMaxTranslationVelocity(999999);
329  }
330 
331  void planeToABC(vpPlane &pl, double &A, double &B, double &C)
332  {
333  if (fabs(pl.getD()) < std::numeric_limits<double>::epsilon()) {
334  std::cout << "Invalid position:" << std::endl;
335  std::cout << m_cMo << std::endl;
336  std::cout << "Cannot put plane in the form 1/Z=Ax+By+C." << std::endl;
337  throw vpException(vpException::divideByZeroError, "invalid position!");
338  }
339  A = -pl.getA() / pl.getD();
340  B = -pl.getB() / pl.getD();
341  C = -pl.getC() / pl.getD();
342  }
343 
344  // setup robot parameters
345  void paramRobot()
346  {
347  /*Initialise the robot and especially the camera*/
349  m_robot.setCurrentViewColor(vpColor(150, 150, 150));
350  m_robot.setDesiredViewColor(vpColor(200, 200, 200));
351  m_robot.setRobotState(vpRobot::STATE_VELOCITY_CONTROL);
352  removeJointLimits(m_robot);
354  m_robot.setConstantSamplingTimeMode(true);
355  /*Initialise the position of the object relative to the pose of the robot's
356  * camera*/
357  m_robot.initialiseObjectRelativeToCamera(m_cMo);
358 
359  /*Set the desired position (for the displaypart)*/
360  m_robot.setDesiredCameraPosition(m_cdMo);
361  m_robot.getCameraParameters(m_cam, m_Iint);
362  }
363 
364  void setInteractionMatrixType(vpServo::vpServoIteractionMatrixType type) { m_interaction_type = type; }
365 
366  double error() { return m_error; }
367 
368  void init_visp_plot(vpPlot &ViSP_plot)
369  {
370  /* -------------------------------------
371  * Initialize ViSP Plotting
372  * -------------------------------------
373  */
374  const unsigned int NbGraphs = 3; // No. of graphs
375  const unsigned int NbCurves_in_graph[NbGraphs] = { 6, 6, 6 }; // Curves in each graph
376 
377  ViSP_plot.init(NbGraphs, 800, 800, 100 + static_cast<int>(m_width), 50, "Visual Servoing results...");
378 
379  vpColor Colors[6] = {// Colour for s1, s2, s3, in 1st plot
381 
382  for (unsigned int p = 0; p < NbGraphs; p++) {
383  ViSP_plot.initGraph(p, NbCurves_in_graph[p]);
384  for (unsigned int c = 0; c < NbCurves_in_graph[p]; c++)
385  ViSP_plot.setColor(p, c, Colors[c]);
386  }
387 
388  ViSP_plot.setTitle(0, "Robot velocities");
389  ViSP_plot.setLegend(0, 0, "v_x");
390  ViSP_plot.setLegend(0, 1, "v_y");
391  ViSP_plot.setLegend(0, 2, "v_z");
392  ViSP_plot.setLegend(0, 3, "w_x");
393  ViSP_plot.setLegend(0, 4, "w_y");
394  ViSP_plot.setLegend(0, 5, "w_z");
395 
396  ViSP_plot.setTitle(1, "Camera pose cMo");
397  ViSP_plot.setLegend(1, 0, "tx");
398  ViSP_plot.setLegend(1, 1, "ty");
399  ViSP_plot.setLegend(1, 2, "tz");
400  ViSP_plot.setLegend(1, 3, "tu_x");
401  ViSP_plot.setLegend(1, 4, "tu_y");
402  ViSP_plot.setLegend(1, 5, "tu_z");
403 
404  ViSP_plot.setTitle(2, "Error in visual features: ");
405  ViSP_plot.setLegend(2, 0, "x_n");
406  ViSP_plot.setLegend(2, 1, "y_n");
407  ViSP_plot.setLegend(2, 2, "a_n");
408  ViSP_plot.setLegend(2, 3, "sx");
409  ViSP_plot.setLegend(2, 4, "sy");
410  ViSP_plot.setLegend(2, 5, "alpha");
411  }
412 
413 protected:
414  // start and destination positioning matrices
415  unsigned int m_width;
416  unsigned int m_height;
417 
418  // start and destination positioning matrices
419  vpHomogeneousMatrix m_cMo;
420  vpHomogeneousMatrix m_cdMo;
421 
422  vpSimulatorAfma6 m_robot; // robot used in this simulation
423  vpImage<vpRGBa> m_Iint; // internal image used for interface display
424  vpServo m_task; // servoing task
425  vpCameraParameters m_cam; // robot camera parameters
426  double m_error; // current error
427  vpImageSimulator m_imsim; // image simulator used to simulate the perspective-projection camera
428 
429  vpServo::vpServoIteractionMatrixType m_interaction_type; // current or desired
430  // source and destination objects for moment manipulation
431  vpMomentObject m_src;
432  vpMomentObject m_dst;
433 
434  // moment sets and their corresponding features
435  vpMomentCommon *m_moments;
436  vpMomentCommon *m_momentsDes;
437  vpFeatureMomentCommon *m_featureMoments;
438  vpFeatureMomentCommon *m_featureMomentsDes;
439 
440  vpDisplay *m_displayInt;
441 };
442 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
443 
444 int main()
445 {
446  try { // intial pose
447  vpHomogeneousMatrix cMo(0.05, 0.1, 1.5, vpMath::rad(30), vpMath::rad(20), -vpMath::rad(15));
448  // Desired pose
450 
451  servoMoment servo;
452  // init and run the simulation
453  servo.init(cMo, cdMo);
454  servo.execute(1500);
455  return EXIT_SUCCESS;
456  }
457  catch (const vpException &e) {
458  std::cout << "Catch an exception: " << e << std::endl;
459  return EXIT_FAILURE;
460  }
461 }
462 
463 #endif
@ TOOL_CCMOP
Definition: vpAfma6.h:124
Generic class defining intrinsic camera parameters.
@ perspectiveProjWithoutDistortion
Perspective projection without distortion model.
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
static const vpColor red
Definition: vpColor.h:211
static const vpColor cyan
Definition: vpColor.h:220
static const vpColor orange
Definition: vpColor.h:221
static const vpColor blue
Definition: vpColor.h:217
static const vpColor purple
Definition: vpColor.h:222
static const vpColor green
Definition: vpColor.h:214
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed....
Definition: vpDisplayD3D.h:101
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:128
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="") vp_override
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:128
Class that defines generic functionalities for display.
Definition: vpDisplay.h:173
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition: vpException.h:59
@ divideByZeroError
Division by zero.
Definition: vpException.h:82
This class allows to access common vpFeatureMoments in a pre-filled database.
Implementation of an homogeneous matrix and operations on such kind of matrices.
Class which enables to project an image in the 3D space and get the view of a virtual camera.
static double rad(double deg)
Definition: vpMath.h:127
This class initializes and allows access to commonly used moments.
static std::vector< double > getMu3(vpMomentObject &object)
static double getAlpha(vpMomentObject &object)
static double getSurface(vpMomentObject &object)
Class for generic objects.
void setType(vpObjectType input_type)
void fromVector(std::vector< vpPoint > &points)
This class defines the container for a plane geometrical structure.
Definition: vpPlane.h:54
void changeFrame(const vpHomogeneousMatrix &cMo)
Definition: vpPlane.cpp:372
double getD() const
Definition: vpPlane.h:106
double getA() const
Definition: vpPlane.h:100
double getC() const
Definition: vpPlane.h:104
void setABCD(double a, double b, double c, double d)
Definition: vpPlane.h:88
double getB() const
Definition: vpPlane.h:102
This class enables real time drawing of 2D or 3D graphics. An instance of the class open a window whi...
Definition: vpPlot.h:109
void initGraph(unsigned int graphNum, unsigned int curveNbr)
Definition: vpPlot.cpp:202
void init(unsigned int nbGraph, unsigned int height=700, unsigned int width=700, int x=-1, int y=-1, const std::string &title="")
Definition: vpPlot.cpp:95
void setLegend(unsigned int graphNum, unsigned int curveNum, const std::string &legend)
Definition: vpPlot.cpp:545
void plot(unsigned int graphNum, unsigned int curveNum, double x, double y)
Definition: vpPlot.cpp:269
void setColor(unsigned int graphNum, unsigned int curveNum, vpColor color)
Definition: vpPlot.cpp:245
void setTitle(unsigned int graphNum, const std::string &title)
Definition: vpPlot.cpp:503
Class that defines a 3D point in the object frame and allows forward projection of a 3D point in the ...
Definition: vpPoint.h:77
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:189
@ CAMERA_FRAME
Definition: vpRobot.h:82
@ STATE_VELOCITY_CONTROL
Initialize the velocity controller.
Definition: vpRobot.h:65
void setMaxRotationVelocity(double maxVr)
Definition: vpRobot.cpp:257
void setMaxTranslationVelocity(double maxVt)
Definition: vpRobot.cpp:236
@ EYEINHAND_CAMERA
Definition: vpServo.h:155
vpServoIteractionMatrixType
Definition: vpServo.h:190
@ CURRENT
Definition: vpServo.h:196
Simulator of Irisa's gantry robot named Afma6.
Class that consider the case of a translation vector.
void init(vpImage< unsigned char > &Iinput, vpImage< unsigned char > &IcannyVisp, vpImage< unsigned char > *p_dIx, vpImage< unsigned char > *p_dIy, vpImage< unsigned char > *p_IcannyimgFilter)
Initialize the different displays.