Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
servoSimuCylinder2DCamVelocityDisplaySecondaryTask.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 * Simulation of a 2D visual servoing on a cylinder.
32 */
48
49#include <iostream>
50#include <stdio.h>
51#include <stdlib.h>
52
53#include <visp3/core/vpCameraParameters.h>
54#include <visp3/core/vpConfig.h>
55#include <visp3/core/vpCylinder.h>
56#include <visp3/core/vpHomogeneousMatrix.h>
57#include <visp3/core/vpImage.h>
58#include <visp3/core/vpMath.h>
59#include <visp3/gui/vpDisplayFactory.h>
60#include <visp3/gui/vpProjectionDisplay.h>
61#include <visp3/io/vpParseArgv.h>
62#include <visp3/robot/vpSimulatorCamera.h>
63#include <visp3/visual_features/vpFeatureBuilder.h>
64#include <visp3/visual_features/vpFeatureLine.h>
65#include <visp3/vs/vpServo.h>
66#include <visp3/vs/vpServoDisplay.h>
67
68// List of allowed command line options
69#define GETOPTARGS "cdho"
70
71#ifdef ENABLE_VISP_NAMESPACE
72using namespace VISP_NAMESPACE_NAME;
73#endif
74
75void usage(const char *name, const char *badparam);
76bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
77
86void usage(const char *name, const char *badparam)
87{
88 fprintf(stdout, "\n\
89Simulation of a 2D visual servoing on a cylinder:\n\
90- eye-in-hand control law,\n\
91- velocity computed in the camera frame,\n\
92- display the camera view.\n\
93 \n\
94SYNOPSIS\n\
95 %s [-c] [-d] [-o] [-h]\n",
96 name);
97
98 fprintf(stdout, "\n\
99OPTIONS: Default\n\
100 \n\
101 -c\n\
102 Disable the mouse click. Useful to automate the \n\
103 execution of this program without human intervention.\n\
104 \n\
105 -d \n\
106 Turn off the display.\n\
107 \n\
108 -o \n\
109 Disable new projection operator usage for secondary task.\n\
110 \n\
111 -h\n\
112 Print the help.\n");
113
114 if (badparam)
115 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
116}
117
130bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display, bool &new_proj_operator)
131{
132 const char *optarg_;
133 int c;
134 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
135
136 switch (c) {
137 case 'c':
138 click_allowed = false;
139 break;
140 case 'd':
141 display = false;
142 break;
143 case 'o':
144 new_proj_operator = false;
145 break;
146 case 'h':
147 usage(argv[0], nullptr);
148 return false;
149
150 default:
151 usage(argv[0], optarg_);
152 return false;
153 }
154 }
155
156 if ((c == 1) || (c == -1)) {
157 // standalone param or error
158 usage(argv[0], nullptr);
159 std::cerr << "ERROR: " << std::endl;
160 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
161 return false;
162 }
163
164 return true;
165}
166
167int main(int argc, const char **argv)
168{
169 // We declare the windows variables to be able to free the memory in the catch sections if needed
170#ifdef VISP_HAVE_DISPLAY
171#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
172 std::shared_ptr<vpDisplay> displayInt;
173 std::shared_ptr<vpDisplay> displayExt;
174#else
175 vpDisplay *displayInt = nullptr;
176 vpDisplay *displayExt = nullptr;
177#endif
178#endif
179#if (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
180 try {
181 bool opt_display = true;
182 bool opt_click_allowed = true;
183 bool opt_new_proj_operator = true;
184
185 // Read the command line options
186 if (getOptions(argc, argv, opt_click_allowed, opt_display, opt_new_proj_operator) == false) {
187 return EXIT_FAILURE;
188 }
189
190 vpImage<unsigned char> Iint(512, 512, 0);
191 vpImage<unsigned char> Iext(512, 512, 0);
192
193 if (opt_display) {
194#ifdef VISP_HAVE_DISPLAY
195 // Display size is automatically defined by the image (Iint) and
196 // (Iext) size
197#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
198 displayInt = vpDisplayFactory::createDisplay(Iint, 100, 100, "Internal view");
199 displayExt = vpDisplayFactory::createDisplay(Iext, 130 + static_cast<int>(Iint.getWidth()), 100, "External view");
200#else
201 displayInt = vpDisplayFactory::allocateDisplay(Iint, 100, 100, "Internal view");
202 displayExt = vpDisplayFactory::allocateDisplay(Iext, 130 + static_cast<int>(Iint.getWidth()), 100, "External view");
203#endif
204#endif
205 // Display the image
206 // The image class has a member that specify a pointer toward
207 // the display that has been initialized in the display declaration
208 // therefore is is no longer necessary to make a reference to the
209 // display variable.
210 vpDisplay::display(Iint);
211 vpDisplay::display(Iext);
212 vpDisplay::flush(Iint);
213 vpDisplay::flush(Iext);
214 }
215
216#ifdef VISP_HAVE_DISPLAY
217 vpProjectionDisplay externalview;
218#endif
219
220 // Set the camera parameters
221 double px, py;
222 px = py = 600;
223 double u0, v0;
224 u0 = v0 = 256;
225
226 vpCameraParameters cam(px, py, u0, v0);
227
229 vpSimulatorCamera robot;
230
231 // sets the initial camera location
232 vpHomogeneousMatrix cMo(-0.2, 0.1, 2, vpMath::rad(5), vpMath::rad(5), vpMath::rad(20));
233
234 vpHomogeneousMatrix wMc, wMo;
235 robot.getPosition(wMc);
236 wMo = wMc * cMo; // Compute the position of the object in the world frame
237
238 // sets the final camera location (for simulation purpose)
239 vpHomogeneousMatrix cMod(0, 0, 1, vpMath::rad(0), vpMath::rad(0), vpMath::rad(0));
240
241 // sets the cylinder coordinates in the world frame
242 vpCylinder cylinder(0, 1, 0, // direction
243 0, 0, 0, // point of the axis
244 0.1); // radius
245
246#ifdef VISP_HAVE_DISPLAY
247 externalview.insert(cylinder);
248#endif
249 // sets the desired position of the visual feature
250 cylinder.track(cMod);
251 cylinder.print();
252
253 // Build the desired line features thanks to the cylinder and especially
254 // its paramaters in the image frame
255 vpFeatureLine ld[2];
256 for (unsigned int i = 0; i < 2; i++)
257 vpFeatureBuilder::create(ld[i], cylinder, i);
258
259 // computes the cylinder coordinates in the camera frame and its 2D
260 // coordinates sets the current position of the visual feature
261 cylinder.track(cMo);
262 cylinder.print();
263
264 // Build the current line features thanks to the cylinder and especially
265 // its paramaters in the image frame
266 vpFeatureLine l[2];
267 for (unsigned int i = 0; i < 2; i++) {
268 vpFeatureBuilder::create(l[i], cylinder, i);
269 l[i].print();
270 }
271
272 // define the task
273 // - we want an eye-in-hand control law
274 // - robot is controlled in the camera frame
276 task.setInteractionMatrixType(vpServo::DESIRED, vpServo::PSEUDO_INVERSE);
277 // it can also be interesting to test these possibilities
278 // task.setInteractionMatrixType(vpServo::CURRENT,vpServo::PSEUDO_INVERSE)
279 // ; task.setInteractionMatrixType(vpServo::MEAN, vpServo::PSEUDO_INVERSE)
280 // ; task.setInteractionMatrixType(vpServo::CURRENT,
281 // vpServo::PSEUDO_INVERSE) ;
282 // task.setInteractionMatrixType(vpServo::DESIRED, vpServo::TRANSPOSE) ;
283 // task.setInteractionMatrixType(vpServo::CURRENT, vpServo::TRANSPOSE) ;
284
285 // we want to see 2 lines on 2 lines
286 task.addFeature(l[0], ld[0]);
287 task.addFeature(l[1], ld[1]);
288
289 // Set the point of view of the external view
290 vpHomogeneousMatrix cextMo(0, 0, 6, vpMath::rad(40), vpMath::rad(10), vpMath::rad(60));
291
292 // Display the initial scene
293 vpServoDisplay::display(task, cam, Iint);
294#ifdef VISP_HAVE_DISPLAY
295 externalview.display(Iext, cextMo, cMo, cam, vpColor::red);
296#endif
297 vpDisplay::flush(Iint);
298 vpDisplay::flush(Iext);
299
300 // Display task information
301 task.print();
302
303 if (opt_display && opt_click_allowed) {
304 vpDisplay::displayText(Iint, 20, 20, "Click to start visual servo...", vpColor::white);
305 vpDisplay::flush(Iint);
307 }
308
309 // set the gain
310 task.setLambda(1);
311
312 // Display task information
313 task.print();
314
315 unsigned int iter = 0;
316 bool stop = false;
317 bool start_secondary_task = false;
318
319 while (!stop) {
320 std::cout << "---------------------------------------------" << iter++ << std::endl;
321
322 // get the robot position
323 robot.getPosition(wMc);
324 // Compute the position of the object frame in the camera frame
325 cMo = wMc.inverse() * wMo;
326
327 // new line position
328 // retrieve x,y and Z of the vpLine structure
329 // Compute the parameters of the cylinder in the camera frame and in the
330 // image frame
331 cylinder.track(cMo);
332
333 // Build the current line features thanks to the cylinder and especially
334 // its paramaters in the image frame
335 for (unsigned int i = 0; i < 2; i++) {
336 vpFeatureBuilder::create(l[i], cylinder, i);
337 }
338
339 // Display the current scene
340 if (opt_display) {
341 vpDisplay::display(Iint);
342 vpDisplay::display(Iext);
343 vpServoDisplay::display(task, cam, Iint);
344#ifdef VISP_HAVE_DISPLAY
345 externalview.display(Iext, cextMo, cMo, cam, vpColor::red);
346#endif
347 }
348
349 // compute the control law
350 vpColVector v = task.computeControlLaw();
351
352 // Wait primary task convergence before considering secondary task
353 if (task.getError().sumSquare() < 1e-6) {
354 start_secondary_task = true;
355 }
356
357 if (start_secondary_task) {
358 // In this example the secondary task is cut in four
359 // steps. The first one consists in imposing a movement of the robot along
360 // the x axis of the object frame with a velocity of 0.5. The second one
361 // consists in imposing a movement of the robot along the y axis of the
362 // object frame with a velocity of 0.5. The third one consists in imposing a
363 // movement of the robot along the x axis of the object frame with a
364 // velocity of -0.5. The last one consists in imposing a movement of the
365 // robot along the y axis of the object frame with a velocity of -0.5.
366 // Each steps is made during 200 iterations.
367 vpColVector e1(6);
368 vpColVector e2(6);
369 vpColVector proj_e1;
370 vpColVector proj_e2;
371 static unsigned int iter_sec = 0;
372 double rapport = 0;
373 double vitesse = 0.5;
374 unsigned int tempo = 800;
375
376 if (iter_sec > tempo) {
377 stop = true;
378 }
379
380 if (iter_sec % tempo < 200) {
381 e2 = 0;
382 e1[0] = fabs(vitesse);
383 proj_e1 = task.secondaryTask(e1, opt_new_proj_operator);
384 rapport = vitesse / proj_e1[0];
385 proj_e1 *= rapport;
386 v += proj_e1;
387 }
388
389 if (iter_sec % tempo < 400 && iter_sec % tempo >= 200) {
390 e1 = 0;
391 e2[1] = fabs(vitesse);
392 proj_e2 = task.secondaryTask(e2, opt_new_proj_operator);
393 rapport = vitesse / proj_e2[1];
394 proj_e2 *= rapport;
395 v += proj_e2;
396 }
397
398 if (iter_sec % tempo < 600 && iter_sec % tempo >= 400) {
399 e2 = 0;
400 e1[0] = -fabs(vitesse);
401 proj_e1 = task.secondaryTask(e1, opt_new_proj_operator);
402 rapport = -vitesse / proj_e1[0];
403 proj_e1 *= rapport;
404 v += proj_e1;
405 }
406
407 if (iter_sec % tempo < 800 && iter_sec % tempo >= 600) {
408 e1 = 0;
409 e2[1] = -fabs(vitesse);
410 proj_e2 = task.secondaryTask(e2, opt_new_proj_operator);
411 rapport = -vitesse / proj_e2[1];
412 proj_e2 *= rapport;
413 v += proj_e2;
414 }
415
416 if (opt_display && opt_click_allowed) {
417 std::stringstream ss;
418 ss << std::string("New projection operator: ") +
419 (opt_new_proj_operator ? std::string("yes (use option -o to use old one)") : std::string("no"));
420 vpDisplay::displayText(Iint, 20, 20, "Secondary task enabled: yes", vpColor::white);
421 vpDisplay::displayText(Iint, 40, 20, ss.str(), vpColor::white);
422 }
423
424 iter_sec++;
425 }
426 else {
427 if (opt_display && opt_click_allowed) {
428 vpDisplay::displayText(Iint, 20, 20, "Secondary task: no", vpColor::white);
429 }
430 }
431
432 // send the camera velocity to the controller
433 robot.setVelocity(vpRobot::CAMERA_FRAME, v);
434
435 std::cout << "|| s - s* || = " << (task.getError()).sumSquare() << std::endl;
436
437 if (opt_display) {
438 vpDisplay::displayText(Iint, 60, 20, "Click to stop visual servo...", vpColor::white);
439 if (vpDisplay::getClick(Iint, false)) {
440 stop = true;
441 }
442 vpDisplay::flush(Iint);
443 vpDisplay::flush(Iext);
444 }
445
446 iter++;
447 }
448
449 if (opt_display && opt_click_allowed) {
450 vpDisplay::display(Iint);
451 vpServoDisplay::display(task, cam, Iint);
452 vpDisplay::displayText(Iint, 20, 20, "Click to quit...", vpColor::white);
453 vpDisplay::flush(Iint);
455 }
456
457 // Display task information
458 task.print();
459#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
460 if (displayInt != nullptr) {
461 delete displayInt;
462 }
463 if (displayExt != nullptr) {
464 delete displayExt;
465 }
466#endif
467 return EXIT_SUCCESS;
468 }
469 catch (const vpException &e) {
470 std::cout << "Catch a ViSP exception: " << e << std::endl;
471#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
472 if (displayInt != nullptr) {
473 delete displayInt;
474 }
475 if (displayExt != nullptr) {
476 delete displayExt;
477 }
478#endif
479 return EXIT_FAILURE;
480 }
481#else
482 (void)argc;
483 (void)argv;
484 std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
485 return EXIT_SUCCESS;
486#endif
487}
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
static const vpColor white
Definition vpColor.h:193
static const vpColor red
Definition vpColor.h:198
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 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: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 ,...
void print(unsigned int select=FEATURE_ALL) const VP_OVERRIDE
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
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
interface with the image for feature display
void insert(vpForwardProjection &fp)
void display(vpImage< unsigned char > &I, const vpHomogeneousMatrix &cextMo, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &color, const bool &displayTraj=false, unsigned int thickness=1)
@ CAMERA_FRAME
Definition vpRobot.h:81
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)
@ EYEINHAND_CAMERA
Definition vpServo.h:176
@ PSEUDO_INVERSE
Definition vpServo.h:250
@ DESIRED
Definition vpServo.h:223
Class that defines the simplest robot: a free flying camera.
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.