Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
servoSimuCylinder.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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 https://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 * Demonstration of the wireframe simulator with a simple visual servoing
32 */
33
39
40#include <stdlib.h>
41
42#include <visp3/core/vpCameraParameters.h>
43#include <visp3/core/vpCylinder.h>
44#include <visp3/core/vpHomogeneousMatrix.h>
45#include <visp3/core/vpImage.h>
46#include <visp3/core/vpIoTools.h>
47#include <visp3/core/vpMath.h>
48#include <visp3/core/vpTime.h>
49#include <visp3/core/vpVelocityTwistMatrix.h>
50#include <visp3/gui/vpDisplayFactory.h>
51#include <visp3/gui/vpPlot.h>
52#include <visp3/io/vpImageIo.h>
53#include <visp3/io/vpParseArgv.h>
54#include <visp3/robot/vpSimulatorCamera.h>
55#include <visp3/robot/vpWireFrameSimulator.h>
56#include <visp3/visual_features/vpFeatureBuilder.h>
57#include <visp3/vs/vpServo.h>
58
59#define GETOPTARGS "dhp"
60
61#if defined(VISP_HAVE_DISPLAY) && (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
62
63#if defined(ENABLE_VISP_NAMESPACE)
64using namespace VISP_NAMESPACE_NAME;
65#endif
66
75void usage(const char *name, const char *badparam)
76{
77 fprintf(stdout, "\n\
78Demonstration of the wireframe simulator with a simple visual servoing.\n\
79 \n\
80The visual servoing consists in bringing the camera at a desired position\n\
81from the object.\n\
82 \n\
83The visual features used to compute the pose of the camera and \n\
84thus the control law are two lines. These features are computed thanks \n\
85to the equation of a cylinder.\n\
86 \n\
87This demonstration explains also how to move the object around a world \n\
88reference frame. Here, the movment is a rotation around the x and y axis \n\
89at a given distance from the world frame. In fact the object trajectory \n\
90is on a sphere whose center is the origin of the world frame.\n\
91 \n\
92SYNOPSIS\n\
93 %s [-d] [-p] [-h]\n",
94 name);
95
96 fprintf(stdout, "\n\
97OPTIONS: \n\
98 -d \n\
99 Turn off the display.\n\
100 \n\
101 -p \n\
102 Turn off the plotter.\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
123bool getOptions(int argc, const char **argv, bool &display, bool &plot)
124{
125 const char *optarg_;
126 int c;
127 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
128
129 switch (c) {
130 case 'd':
131 display = false;
132 break;
133 case 'p':
134 plot = false;
135 break;
136 case 'h':
137 usage(argv[0], nullptr);
138 return false;
139
140 default:
141 usage(argv[0], optarg_);
142 return false;
143 }
144 }
145
146 if ((c == 1) || (c == -1)) {
147 // standalone param or error
148 usage(argv[0], nullptr);
149 std::cerr << "ERROR: " << std::endl;
150 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
151 return false;
152 }
153
154 return true;
155}
156
157int main(int argc, const char **argv)
158{
159 const unsigned int NB_DISPLAYS = 2;
160#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
161 std::shared_ptr<vpDisplay> display[NB_DISPLAYS];
162 for (unsigned int i = 0; i < NB_DISPLAYS; ++i) {
164 }
165#else
166 vpDisplay *display[NB_DISPLAYS];
167 for (unsigned int i = 0; i < NB_DISPLAYS; ++i) {
169 }
170#endif
171 unsigned int exit_status = EXIT_SUCCESS;
172
173 try {
174 bool opt_display = true;
175 bool opt_plot = true;
176
177 // Read the command line options
178 if (getOptions(argc, argv, opt_display, opt_plot) == false) {
179 return EXIT_FAILURE;
180 }
181
182 vpImage<vpRGBa> Iint(480, 640, vpRGBa(255));
183 vpImage<vpRGBa> Iext(480, 640, vpRGBa(255));
184
185 if (opt_display) {
186 // Display size is automatically defined by the image (I) size
187 display[0]->init(Iint, 100, 100, "The internal view");
188 display[1]->init(Iext, 100, 100, "The first external view");
190 vpDisplay::setWindowPosition(Iext, 750, 0);
191 vpDisplay::display(Iint);
192 vpDisplay::flush(Iint);
193 vpDisplay::display(Iext);
194 vpDisplay::flush(Iext);
195 }
196
197 vpPlot *plotter = nullptr;
198
200 vpSimulatorCamera robot;
201 float sampling_time = 0.020f; // Sampling period in second
202 robot.setSamplingTime(sampling_time);
203
204 // Set initial position of the object in the camera frame
205 vpHomogeneousMatrix cMo(0, 0.1, 0.3, vpMath::rad(35), vpMath::rad(25), vpMath::rad(75));
206 // Set desired position of the object in the camera frame
207 vpHomogeneousMatrix cdMo(0.0, 0.0, 0.5, vpMath::rad(90), vpMath::rad(0), vpMath::rad(0));
208 // Set initial position of the object in the world frame
209 vpHomogeneousMatrix wMo(0.0, 0.0, 0, 0, 0, 0);
210 // Position of the camera in the world frame
212 wMc = wMo * cMo.inverse();
213
214 // Create a cylinder
215 vpCylinder cylinder(0, 0, 1, 0, 0, 0, 0.1);
216
217 // Projection of the cylinder
218 cylinder.track(cMo);
219
220 // Set the current visual feature
221 vpFeatureLine l[2];
224
225 // Projection of the cylinder
226 cylinder.track(cdMo);
227
228 vpFeatureLine ld[2];
231
233 task.setInteractionMatrixType(vpServo::DESIRED);
234
236 vpVelocityTwistMatrix cVe(cMe);
237 task.set_cVe(cVe);
238
239 vpMatrix eJe;
240 robot.get_eJe(eJe);
241 task.set_eJe(eJe);
242
243 for (int i = 0; i < 2; i++)
244 task.addFeature(l[i], ld[i]);
245
246 if (opt_plot) {
247 plotter = new vpPlot(2, 480, 640, 750, 550, "Real time curves plotter");
248 plotter->setTitle(0, "Visual features error");
249 plotter->setTitle(1, "Camera velocities");
250 plotter->initGraph(0, task.getDimension());
251 plotter->initGraph(1, 6);
252 plotter->setLegend(0, 0, "error_feat_l1_rho");
253 plotter->setLegend(0, 1, "error_feat_l1_theta");
254 plotter->setLegend(0, 2, "error_feat_l2_rho");
255 plotter->setLegend(0, 3, "error_feat_l2_theta");
256 plotter->setLegend(1, 0, "vc_x");
257 plotter->setLegend(1, 1, "vc_y");
258 plotter->setLegend(1, 2, "vc_z");
259 plotter->setLegend(1, 3, "wc_x");
260 plotter->setLegend(1, 4, "wc_y");
261 plotter->setLegend(1, 5, "wc_z");
262 }
263
264 task.setLambda(1);
265
267
268 // Set the scene
270
271 // Initialize simulator frames
272 sim.set_fMo(wMo); // Position of the object in the world reference frame
273 sim.setCameraPositionRelObj(cMo); // Initial position of the object in the camera frame
274 sim.setDesiredCameraPosition(cdMo); // Desired position of the object in the camera frame
275
276 // Set the External camera position
277 vpHomogeneousMatrix camMf(vpHomogeneousMatrix(0.0, 0, 3.5, vpMath::rad(0), vpMath::rad(30), 0));
278 sim.setExternalCameraPosition(camMf);
279
280 // Set the parameters of the cameras (internal and external)
281 vpCameraParameters camera(1000, 1000, 320, 240);
282 sim.setInternalCameraParameters(camera);
283 sim.setExternalCameraParameters(camera);
284
285 int max_iter = 10;
286
287 if (opt_display) {
288 max_iter = 2500;
289
290 // Get the internal and external views
291 sim.getInternalImage(Iint);
292 sim.getExternalImage(Iext);
293
294 // Display the object frame (current and desired position)
295 vpDisplay::displayFrame(Iint, cMo, camera, 0.2, vpColor::none);
296 vpDisplay::displayFrame(Iint, cdMo, camera, 0.2, vpColor::none);
297
298 // Display the object frame the world reference frame and the camera
299 // frame
300 vpDisplay::displayFrame(Iext, camMf * sim.get_fMo() * cMo.inverse(), camera, 0.2, vpColor::none);
301 vpDisplay::displayFrame(Iext, camMf * sim.get_fMo(), camera, 0.2, vpColor::none);
302 vpDisplay::displayFrame(Iext, camMf, camera, 0.2, vpColor::none);
303
304 vpDisplay::displayText(Iint, 20, 20, "Click to start visual servo", vpColor::red);
305
306 vpDisplay::flush(Iint);
307 vpDisplay::flush(Iext);
308
309 std::cout << "Click on a display" << std::endl;
310 while (!vpDisplay::getClick(Iint, false) && !vpDisplay::getClick(Iext, false)) {
311 }
312 }
313
314 robot.setPosition(wMc);
315
316 // Print the task
317 task.print();
318
319 int iter = 0;
320 bool stop = false;
322
323 // Set the secondary task parameters
324 vpColVector e1(6, 0);
325 vpColVector e2(6, 0);
326 vpColVector proj_e1;
327 vpColVector proj_e2;
328 double rapport = 0;
329 double vitesse = 0.3;
330 int tempo = 600;
331
332 double t_prev, t = vpTime::measureTimeMs();
333
334 while (iter++ < max_iter && !stop) {
335 t_prev = t;
337
338 if (opt_display) {
339 vpDisplay::display(Iint);
340 vpDisplay::display(Iext);
341 }
342
343 robot.get_eJe(eJe);
344 task.set_eJe(eJe);
345
346 wMc = robot.getPosition();
347 cMo = wMc.inverse() * wMo;
348
349 cylinder.track(cMo);
352
353 v = task.computeControlLaw();
354
355 // Compute the velocity with the secondary task
356 if (iter % tempo < 200 && iter % tempo >= 0) {
357 e2 = 0;
358 e1[0] = -fabs(vitesse);
359 proj_e1 = task.secondaryTask(e1, true);
360 rapport = -vitesse / proj_e1[0];
361 proj_e1 *= rapport;
362 v += proj_e1;
363 }
364
365 else if (iter % tempo < 300 && iter % tempo >= 200) {
366 e1 = 0;
367 e2[1] = -fabs(vitesse);
368 proj_e2 = task.secondaryTask(e2, true);
369 rapport = -vitesse / proj_e2[1];
370 proj_e2 *= rapport;
371 v += proj_e2;
372 }
373
374 else if (iter % tempo < 500 && iter % tempo >= 300) {
375 e2 = 0;
376 e1[0] = -fabs(vitesse);
377 proj_e1 = task.secondaryTask(e1, true);
378 rapport = vitesse / proj_e1[0];
379 proj_e1 *= rapport;
380 v += proj_e1;
381 }
382
383 else if (iter % tempo < 600 && iter % tempo >= 500) {
384 e1 = 0;
385 e2[1] = -fabs(vitesse);
386 proj_e2 = task.secondaryTask(e2, true);
387 rapport = vitesse / proj_e2[1];
388 proj_e2 *= rapport;
389 v += proj_e2;
390 }
391
392 robot.setVelocity(vpRobot::CAMERA_FRAME, v);
393
394 // Update the simulator frames
395 sim.set_fMo(wMo); // This line is not really requested since the object
396 // doesn't move
398
399 if (opt_plot) {
400 plotter->plot(0, iter, task.getError());
401 plotter->plot(1, iter, v);
402 }
403
404 if (opt_display) {
405 // Get the internal and external views
406 sim.getInternalImage(Iint);
407 sim.getExternalImage(Iext);
408
409 // Display the object frame (current and desired position)
410 vpDisplay::displayFrame(Iint, cMo, camera, 0.2, vpColor::none);
411 vpDisplay::displayFrame(Iint, cdMo, camera, 0.2, vpColor::none);
412
413 // Display the object frame the world reference frame and the camera
414 // frame
415 vpDisplay::displayFrame(Iext, sim.getExternalCameraPosition() * sim.get_fMo() * cMo.inverse(), camera, 0.2,
419
420 vpDisplay::displayText(Iint, 20, 20, "Click to stop visual servo", vpColor::red);
421
422 std::stringstream ss;
423 ss << "Loop time: " << t - t_prev << " ms";
424 vpDisplay::displayText(Iint, 40, 20, ss.str(), vpColor::red);
425
426 if (vpDisplay::getClick(Iint, false)) {
427 stop = true;
428 }
429
430 vpDisplay::flush(Iext);
431 vpDisplay::flush(Iint);
432
433 vpTime::wait(t, sampling_time * 1000); // Wait ms
434 }
435
436 std::cout << "|| s - s* || = " << (task.getError()).sumSquare() << std::endl;
437 }
438
439 if (opt_plot && plotter != nullptr) {
440 vpDisplay::display(Iint);
441 sim.getInternalImage(Iint);
442 vpDisplay::displayFrame(Iint, cMo, camera, 0.2, vpColor::none);
443 vpDisplay::displayFrame(Iint, cdMo, camera, 0.2, vpColor::none);
444 vpDisplay::displayText(Iint, 20, 20, "Click to quit", vpColor::red);
445 if (vpDisplay::getClick(Iint)) {
446 stop = true;
447 }
448 vpDisplay::flush(Iint);
449
450 delete plotter;
451 }
452
453 task.print();
454
455 exit_status = EXIT_SUCCESS;
456 }
457 catch (const vpException &e) {
458 std::cout << "Catch an exception: " << e << std::endl;
459 exit_status = EXIT_FAILURE;
460 }
461#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
462 for (unsigned int i = 0; i < NB_DISPLAYS; ++i) {
463 delete display[i];
464 }
465#endif
466 return exit_status;
467}
468#elif !(defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
469int main()
470{
471 std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
472 return EXIT_SUCCESS;
473}
474#else
475int main()
476{
477 std::cout << "You do not have X11, or GDI (Graphical Device Interface), or GTK functionalities to display images..."
478 << std::endl;
479 std::cout << "Tip if you are on a unix-like system:" << std::endl;
480 std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
481 std::cout << "Tip if you are on a windows-like system:" << std::endl;
482 std::cout << "- Install GDI, configure again ViSP using cmake and build again this example" << std::endl;
483 return EXIT_SUCCESS;
484}
485
486#endif
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
static const vpColor red
Definition vpColor.h:198
static const vpColor none
Definition vpColor.h:210
Class that defines a 3D cylinder in the object frame and allows forward projection of a 3D cylinder i...
Definition vpCylinder.h:101
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
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), const std::string &frameName="", const vpColor &textColor=vpColor::black, const vpImagePoint &textOffset=vpImagePoint(15, 15))
static void flush(const vpImage< unsigned char > &I)
static void setWindowPosition(const vpImage< unsigned char > &I, int winx, int winy)
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:60
static void create(vpFeaturePoint &s, const vpCameraParameters &cam, const vpDot &d)
Class that defines a 2D line visual feature which is composed by two parameters that are and ,...
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
Definition of the vpImage class member functions.
Definition vpImage.h:131
static double rad(double deg)
Definition vpMath.h:129
Implementation of a matrix and operations on matrices.
Definition vpMatrix.h:175
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
This class enables real time drawing of 2D or 3D graphics. An instance of the class open a window whi...
Definition vpPlot.h:117
virtual void setSamplingTime(const double &delta_t)
@ CAMERA_FRAME
Definition vpRobot.h:81
@ EYEINHAND_L_cVe_eJe
Definition vpServo.h:183
@ DESIRED
Definition vpServo.h:223
Class that defines the simplest robot: a free flying camera.
Implementation of a wire frame simulator. Compared to the vpSimulator class, it does not require thir...
vpHomogeneousMatrix getExternalCameraPosition() const
void setCameraPositionRelObj(const vpHomogeneousMatrix &cMo_)
void getInternalImage(vpImage< unsigned char > &I)
void initScene(const vpSceneObject &obj, const vpSceneDesiredObject &desiredObject)
void setExternalCameraPosition(const vpHomogeneousMatrix &cam_Mf)
void set_fMo(const vpHomogeneousMatrix &fMo_)
vpHomogeneousMatrix get_fMo() const
void setDesiredCameraPosition(const vpHomogeneousMatrix &cdMo_)
void setInternalCameraParameters(const vpCameraParameters &cam)
void setExternalCameraParameters(const vpCameraParameters &cam)
@ CYLINDER
A cylinder of 80cm length and 10cm radius.
void getExternalImage(vpImage< unsigned char > &I)
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT double measureTimeMs()
VISP_EXPORT int wait(double t0, double t)