Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
servoSimuSphere2DCamVelocityDisplaySecondaryTask.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 sphere.
32 */
33
43
44#include <stdio.h>
45#include <stdlib.h>
46
47#include <visp3/core/vpConfig.h>
48#include <visp3/core/vpHomogeneousMatrix.h>
49#include <visp3/core/vpMath.h>
50#include <visp3/core/vpSphere.h>
51#include <visp3/gui/vpDisplayFactory.h>
52#include <visp3/gui/vpProjectionDisplay.h>
53#include <visp3/io/vpParseArgv.h>
54#include <visp3/robot/vpSimulatorCamera.h>
55#include <visp3/visual_features/vpFeatureBuilder.h>
56#include <visp3/visual_features/vpFeatureEllipse.h>
57#include <visp3/vs/vpServo.h>
58#include <visp3/vs/vpServoDisplay.h>
59
60// List of allowed command line options
61#define GETOPTARGS "cdho"
62
63#ifdef ENABLE_VISP_NAMESPACE
64using namespace VISP_NAMESPACE_NAME;
65#endif
66
67void usage(const char *name, const char *badparam);
68bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
69
78void usage(const char *name, const char *badparam)
79{
80 fprintf(stdout, "\n\
81Simulation of a 2D visual servoing on a sphere:\n\
82- eye-in-hand control law,\n\
83- velocity computed in the camera frame,\n\
84- display the camera view,\n\
85- a secondary task is the added.\n\
86 \n\
87SYNOPSIS\n\
88 %s [-c] [-d] [-o] [-h]\n",
89 name);
90
91 fprintf(stdout, "\n\
92OPTIONS: Default\n\
93 \n\
94 -c\n\
95 Disable the mouse click. Useful to automate the \n\
96 execution of this program without human intervention.\n\
97 \n\
98 -d \n\
99 Turn off the display.\n\
100 \n\
101 -o \n\
102 Disable new projection operator usage for secondary task.\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
124bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display, bool &new_proj_operator)
125{
126 const char *optarg_;
127 int c;
128 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
129
130 switch (c) {
131 case 'c':
132 click_allowed = false;
133 break;
134 case 'd':
135 display = false;
136 break;
137 case 'o':
138 new_proj_operator = false;
139 break;
140 case 'h':
141 usage(argv[0], nullptr);
142 return false;
143
144 default:
145 usage(argv[0], optarg_);
146 return false;
147 }
148 }
149
150 if ((c == 1) || (c == -1)) {
151 // standalone param or error
152 usage(argv[0], nullptr);
153 std::cerr << "ERROR: " << std::endl;
154 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
155 return false;
156 }
157
158 return true;
159}
160
161int main(int argc, const char **argv)
162{
163#if (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
164#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
165 std::shared_ptr<vpDisplay> displayI;
166 std::shared_ptr<vpDisplay> displayExt;
167#else
168 vpDisplay *displayI = nullptr;
169 vpDisplay *displayExt = nullptr;
170#endif
171 try {
172 bool opt_display = true;
173 bool opt_click_allowed = true;
174 bool opt_new_proj_operator = true;
175
176 // Read the command line options
177 if (getOptions(argc, argv, opt_click_allowed, opt_display, opt_new_proj_operator) == false) {
178 return (EXIT_FAILURE);
179 }
180
181 vpImage<unsigned char> I(512, 512, 0);
182 vpImage<unsigned char> Iext(512, 512, 0);
183
184 if (opt_display) {
185#if defined(VISP_HAVE_DISPLAY)
186 // Display size is automatically defined by the image (I) size
187#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
188 displayI = vpDisplayFactory::createDisplay(I, 100, 100, "Camera view...");
189 displayExt = vpDisplayFactory::createDisplay(Iext, 130 + static_cast<int>(I.getWidth()), 100, "External view");
190#else
191 displayI = vpDisplayFactory::allocateDisplay(I, 100, 100, "Camera view...");
192 displayExt = vpDisplayFactory::allocateDisplay(Iext, 130 + static_cast<int>(I.getWidth()), 100, "External view");
193#endif
194#endif
195 // Display the image
196 // The image class has a member that specify a pointer toward
197 // the display that has been initialized in the display declaration
198 // therefore is is no longer necessary to make a reference to the
199 // display variable.
201 vpDisplay::display(Iext);
203 vpDisplay::flush(Iext);
204 }
205
206#ifdef VISP_HAVE_DISPLAY
207 vpProjectionDisplay externalview;
208#endif
209
210 double px = 600, py = 600;
211 double u0 = I.getWidth() / 2., v0 = I.getHeight() / 2.;
212
213 vpCameraParameters cam(px, py, u0, v0);
214
216 vpSimulatorCamera robot;
217
218 // sets the initial camera location
220 cMo[0][3] = 0.1;
221 cMo[1][3] = 0.2;
222 cMo[2][3] = 2;
223 // Compute the position of the object in the world frame
224 vpHomogeneousMatrix wMc, wMo;
225 robot.getPosition(wMc);
226 wMo = wMc * cMo;
227
229 cMod[0][3] = 0;
230 cMod[1][3] = 0;
231 cMod[2][3] = 1;
232
233 // sets the sphere coordinates in the world frame
234 vpSphere sphere;
235 sphere.setWorldCoordinates(0, 0, 0, 0.1);
236
237#ifdef VISP_HAVE_DISPLAY
238 externalview.insert(sphere);
239#endif
240 // sets the desired position of the visual feature
242 sphere.track(cMod);
243 vpFeatureBuilder::create(pd, sphere);
244
245 // computes the sphere coordinates in the camera frame and its 2D
246 // coordinates sets the current position of the visual feature
248 sphere.track(cMo);
249 vpFeatureBuilder::create(p, sphere);
250
251 // define the task
252 // - we want an eye-in-hand control law
253 // - robot is controlled in the camera frame
255
256 // we want to see a sphere on a sphere
257 std::cout << std::endl;
258 task.addFeature(p, pd);
259
260 // set the gain
261 task.setLambda(1);
262
263 // Set the point of view of the external view
264 vpHomogeneousMatrix cextMo(0, 0, 4, vpMath::rad(40), vpMath::rad(10), vpMath::rad(60));
265
266 // Display the initial scene
267 vpServoDisplay::display(task, cam, I);
268#ifdef VISP_HAVE_DISPLAY
269 externalview.display(Iext, cextMo, cMo, cam, vpColor::red);
270#endif
272 vpDisplay::flush(Iext);
273
274 // Display task information
275 task.print();
276
277 if (opt_display && opt_click_allowed) {
278 vpDisplay::displayText(I, 20, 20, "Click to start visual servo...", vpColor::white);
281 }
282
283 unsigned int iter = 0;
284 bool stop = false;
285 bool start_secondary_task = false;
286
287 // loop
288 while (iter++ < 2000 && !stop) {
289 std::cout << "---------------------------------------------" << iter << std::endl;
290
291 // get the robot position
292 robot.getPosition(wMc);
293 // Compute the position of the object frame in the camera frame
294 cMo = wMc.inverse() * wMo;
295
296 // new sphere position: retrieve x,y and Z of the vpSphere structure
297 sphere.track(cMo);
298 vpFeatureBuilder::create(p, sphere);
299
300 if (opt_display) {
302 vpDisplay::display(Iext);
303 vpServoDisplay::display(task, cam, I);
304#ifdef VISP_HAVE_DISPLAY
305 externalview.display(Iext, cextMo, cMo, cam, vpColor::red);
306#endif
307 }
308
309 // compute the control law
310 vpColVector v = task.computeControlLaw();
311
312 // Wait primary task convergence before considering secondary task
313 if (task.getError().sumSquare() < 1e-6) {
314 start_secondary_task = true;
315 }
316
317 if (start_secondary_task) {
318 // Only 3 dof are required to achieve primary task: vz, wx, wy
319 // It remains 3 free dof (vx, vy, wz) that could be used in a secondary task for example to move around the
320 // sphere
321 vpColVector de2dt(6);
322 de2dt[0] = 0.50; // vx = 0.50 m/s should also generate a motion on wy = (I-WpW)de2dt[4]
323 de2dt[1] = 0.25; // vy = 0.25 m/s should generate a motion on wx = (I-WpW)de2dt[3]
324 de2dt[2] = 1; // vz = 1 m/s should be zero in vz = (I-WpW)de2dt[2]
325 de2dt[5] = vpMath::rad(10); // wz = 10 rad/s should generate a motion on (I-WpW)de2dt[5]
326
327 std::cout << "de2dt :" << de2dt.t() << std::endl;
328 vpColVector sec = task.secondaryTask(de2dt, opt_new_proj_operator);
329 std::cout << "(I-WpW)de2dt :" << sec.t() << std::endl;
330
331 v += sec;
332
333 if (opt_display && opt_click_allowed) {
334 std::stringstream ss;
335 ss << std::string("New projection operator: ") +
336 (opt_new_proj_operator ? std::string("yes (use option -o to use old one)") : std::string("no"));
337 vpDisplay::displayText(I, 20, 20, "Secondary task enabled: yes", vpColor::white);
338 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::white);
339 }
340 }
341 else {
342 if (opt_display && opt_click_allowed) {
343 vpDisplay::displayText(I, 20, 20, "Secondary task enabled: no", vpColor::white);
344 }
345 }
346
347 // send the camera velocity to the controller
348 robot.setVelocity(vpRobot::CAMERA_FRAME, v);
349
350 std::cout << "|| s - s* || = " << (task.getError()).sumSquare() << std::endl;
351
352 if (opt_display) {
353 vpDisplay::displayText(I, 60, 20, "Click to stop visual servo...", vpColor::white);
354 if (vpDisplay::getClick(I, false)) {
355 stop = true;
356 }
358 vpDisplay::flush(Iext);
359 }
360 }
361
362 if (opt_display && opt_click_allowed) {
364 vpServoDisplay::display(task, cam, I);
365 vpDisplay::displayText(I, 20, 20, "Click to quit...", vpColor::white);
368 }
369
370 // Display task information
371 task.print();
372#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
373 if (displayI != nullptr) {
374 delete displayI;
375 }
376 if (displayExt != nullptr) {
377 delete displayExt;
378 }
379#endif
380 return EXIT_SUCCESS;
381 }
382 catch (const vpException &e) {
383 std::cout << "Catch a ViSP exception: " << e << std::endl;
384#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
385 if (displayI != nullptr) {
386 delete displayI;
387 }
388 if (displayExt != nullptr) {
389 delete displayExt;
390 }
391#endif
392 return EXIT_FAILURE;
393 }
394#else
395 (void)argc;
396 (void)argv;
397 std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
398 return EXIT_SUCCESS;
399#endif
400}
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
vpRowVector t() const
static const vpColor white
Definition vpColor.h:193
static const vpColor red
Definition vpColor.h:198
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 2D ellipse visual feature.
void track(const vpHomogeneousMatrix &cMo)
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
Class that defines the simplest robot: a free flying camera.
Class that defines a 3D sphere in the object frame and allows forward projection of a 3D sphere in th...
Definition vpSphere.h:80
void setWorldCoordinates(const vpColVector &oP) VP_OVERRIDE
Definition vpSphere.cpp:60
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.