Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
servoAfma6Cylinder2DCamVelocitySecondaryTask.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 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 * tests the control law
32 * eye-in-hand control
33 * velocity computed in the camera frame
34 */
35
49
50#include <iostream>
51
52#include <visp3/core/vpConfig.h>
53
54#if defined(VISP_HAVE_REALSENSE2) && defined(VISP_HAVE_AFMA6)
55
56#include <visp3/core/vpImage.h>
57#include <visp3/gui/vpDisplayFactory.h>
58#include <visp3/io/vpImageIo.h>
59#include <visp3/sensor/vpRealSense2.h>
60#include <visp3/core/vpCylinder.h>
61#include <visp3/core/vpHomogeneousMatrix.h>
62#include <visp3/core/vpMath.h>
63#include <visp3/me/vpMeLine.h>
64#include <visp3/visual_features/vpFeatureBuilder.h>
65#include <visp3/visual_features/vpFeatureLine.h>
66#include <visp3/robot/vpRobotAfma6.h>
67#include <visp3/vs/vpServoDisplay.h>
68#include <visp3/vs/vpServo.h>
69
70#ifdef ENABLE_VISP_NAMESPACE
71using namespace VISP_NAMESPACE_NAME;
72#endif
73
74int main(int argc, char **argv)
75{
76 bool opt_verbose = false;
77 bool opt_adaptive_gain = false;
78
79 for (int i = 1; i < argc; ++i) {
80 if (std::string(argv[i]) == "--verbose") {
81 opt_verbose = true;
82 }
83 else if (std::string(argv[i]) == "--adaptive-gain") {
84 opt_adaptive_gain = true;
85 }
86 else if ((std::string(argv[i]) == "--help") || (std::string(argv[i]) == "-h")) {
87 std::cout
88 << argv[0]
89 << " [--adaptive-gain]"
90 << " [--verbose]"
91 << " [--help] [-h]"
92 << std::endl;
93 return EXIT_SUCCESS;
94 }
95 }
96
97 vpRobotAfma6 robot;
99
100 // Load the end-effector to camera frame transformation obtained
101 // using a camera intrinsic model with distortion
102 robot.init(vpAfma6::TOOL_INTEL_D435_CAMERA, projModel);
103
104#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
105 std::shared_ptr<vpDisplay> display;
106#else
107 vpDisplay *display = nullptr;
108#endif
109
110 try {
111 std::cout << "WARNING: This example will move the robot! "
112 << "Please make sure to have the user stop button at hand!" << std::endl
113 << "Press Enter to continue..." << std::endl;
114 std::cin.ignore();
115
116 vpRealSense2 rs;
117 rs2::config config;
118 unsigned int width = 640, height = 480, fps = 60;
119 config.enable_stream(RS2_STREAM_COLOR, width, height, RS2_FORMAT_RGBA8, fps);
120 config.enable_stream(RS2_STREAM_DEPTH, width, height, RS2_FORMAT_Z16, fps);
121 config.enable_stream(RS2_STREAM_INFRARED, width, height, RS2_FORMAT_Y8, fps);
122 rs.open(config);
123
124 // Warm up camera
126 for (size_t i = 0; i < 10; ++i) {
127 rs.acquire(I);
128 }
129
130#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
131 display = vpDisplayFactory::createDisplay(I, 100, 100, "Current image");
132#else
133 display = vpDisplayFactory::allocateDisplay(I, 100, 100, "Current image");
134#endif
137
138 int nblines = 2;
139 std::vector<vpMeLine> line(nblines);
140
141 vpMe me;
142 me.setRange(10);
143 me.setPointsToTrack(100);
145 me.setThreshold(15);
146 me.setSampleStep(10);
147
148 // Initialize the tracking of the two edges of the cylinder
149 for (int i = 0; i < nblines; ++i) {
150 line[i].setDisplay(vpMeSite::RANGE_RESULT);
151 line[i].setMe(&me);
152
153 line[i].initTracking(I);
154 line[i].track(I);
156 }
157
158 // Get camera intrinsics
160 robot.getCameraParameters(cam, I);
161 std::cout << "cam:\n" << cam << std::endl;
162
163 // Sets the current position of the visual feature ");
164 std::vector<vpFeatureLine> s_line(nblines);
165 for (int i = 0; i < nblines; ++i) {
166 vpFeatureBuilder::create(s_line[i], cam, line[i]);
167 }
168
169 // Sets the desired position of the visual feature ");
170 vpCylinder cylinder(0, 1, 0, 0, 0, 0, 0.04);
171
172 vpHomogeneousMatrix c_M_o(0, 0, 0.4, vpMath::rad(0), vpMath::rad(0), vpMath::rad(0));
173
174 cylinder.project(c_M_o);
175
176 std::vector<vpFeatureLine> s_line_d(nblines);
177 vpFeatureBuilder::create(s_line_d[0], cylinder, vpCylinder::line1);
178 vpFeatureBuilder::create(s_line_d[1], cylinder, vpCylinder::line2);
179
180 {
181 std::cout << "Desired features: " << std::endl;
182 std::cout << " - line 1: rho: " << s_line_d[0].getRho() << " theta: " << vpMath::deg(s_line_d[0].getTheta()) << "deg" << std::endl;
183 std::cout << " - line 2: rho: " << s_line_d[1].getRho() << " theta: " << vpMath::deg(s_line_d[1].getTheta()) << "deg" << std::endl;
184 }
185
186 // {
187 // std::cout << "Desired features: " << std::endl;
188 // std::cout << " - line 1: rho: " << s_d[0].getRho() << " theta: " << vpMath::deg(s_d[0].getTheta()) << "deg" << std::endl;
189 // std::cout << " - line 2: rho: " << s_d[1].getRho() << " theta: " << vpMath::deg(s_d[1].getTheta()) << "deg" << std::endl;
190 // }
191
192 // Next 2 lines are needed to keep the conventions defined in vpMeLine
193 s_line_d[0].setRhoTheta(+fabs(s_line_d[0].getRho()), 0);
194 s_line_d[1].setRhoTheta(+fabs(s_line_d[1].getRho()), M_PI);
195 // {
196 // std::cout << "Modified desired features: " << std::endl;
197 // std::cout << " - line 1: rho: " << s_d[0].getRho() << " theta: " << vpMath::deg(s_d[0].getTheta()) << "deg" << std::endl;
198 // std::cout << " - line 2: rho: " << s_d[1].getRho() << " theta: " << vpMath::deg(s_d[1].getTheta()) << "deg" << std::endl;
199 // }
200
201 // Define the task
203 // - we want an eye-in-hand control law
204 // - robot is controlled in the camera frame
206 task.setInteractionMatrixType(vpServo::DESIRED, vpServo::PSEUDO_INVERSE);
207 // - we want to see a two lines on two lines
208 for (int i = 0; i < nblines; ++i) {
209 task.addFeature(s_line[i], s_line_d[i]);
210 }
211
212 // Set the gain
213 if (opt_adaptive_gain) {
214 vpAdaptiveGain lambda(1.5, 0.4, 30); // lambda(0)=4, lambda(oo)=0.4 and lambda'(0)=30
215 task.setLambda(lambda);
216 }
217 else {
218 task.setLambda(0.5);
219 }
220
221 // Display task information
222 task.print();
223 robot.setRobotState(vpRobot::STATE_VELOCITY_CONTROL);
224
225 vpColVector v_c(6);
226 bool final_quit = false;
227 bool send_velocities = false;
228 double task_error = 1.;
229
230 // First loop to reach the convergence position
231 while ((task_error > 0.00001) && (!final_quit)) {
232 double t_start = vpTime::measureTimeMs();
233
234 rs.acquire(I);
236
237 std::stringstream ss;
238 ss << "Left click to " << (send_velocities ? "stop the robot" : "servo the robot") << ", right click to quit.";
239 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
240
241 // Track the two edges and update the features
242 for (int i = 0; i < nblines; ++i) {
243 line[i].track(I);
244 line[i].display(I, vpColor::red);
245
246 vpFeatureBuilder::create(s_line[i], cam, line[i]);
247 //std::cout << "line " << i << " rho: " << s[i].getRho() << " theta: " << vpMath::deg(s[i].getTheta()) << " deg" << std::endl;
248
249 s_line[i].display(cam, I, vpColor::red);
250 s_line_d[i].display(cam, I, vpColor::green);
251 }
252
253 v_c = task.computeControlLaw();
254 task_error = task.getError().sumSquare();
255
256 if (opt_verbose) {
257 std::cout << "v: " << v_c.t() << std::endl;
258 std::cout << "\t\t || s - s* || = " << task_error << std::endl;
259 }
260
261 if (!send_velocities) {
262 v_c = 0;
263 }
264
265 robot.setVelocity(vpRobot::CAMERA_FRAME, v_c);
266
268
269 ss.str("");
270 ss << "Loop time: " << vpTime::measureTimeMs() - t_start << " ms";
271 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::red);
273
275 if (vpDisplay::getClick(I, button, false)) {
276 switch (button) {
278 send_velocities = !send_velocities;
279 break;
280
282 final_quit = true;
283 break;
284
285 default:
286 break;
287 }
288 }
289 }
290
291 // Second loop is to compute the control while taking into account the secondary task.
292 vpColVector e1(6, 0);
293 vpColVector e2(6, 0);
294 vpColVector proj_e1, proj_e2;
295 unsigned long iter = 0;
296 double secondary_task_speed = 0.02; // 2cm/s
297 unsigned int tempo = 1200;
298
299 while (!final_quit) {
300 double t_start = vpTime::measureTimeMs();
301
302 rs.acquire(I);
304
305 std::stringstream ss;
306 ss << "Left click to " << (send_velocities ? "stop the robot" : "servo the robot") << ", right click to quit.";
307 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
308
309 // Track the two edges and update the features
310 for (int i = 0; i < nblines; ++i) {
311 line[i].track(I);
312 line[i].display(I, vpColor::red);
313
314 vpFeatureBuilder::create(s_line[i], cam, line[i]);
315 //std::cout << "line " << i << " rho: " << s[i].getRho() << " theta: " << vpMath::deg(s[i].getTheta()) << " deg" << std::endl;
316
317 s_line[i].display(cam, I, vpColor::red);
318 s_line_d[i].display(cam, I, vpColor::green);
319 }
320
321 v_c = task.computeControlLaw();
322
323 // Compute the new control law corresponding to the secondary task
324 if (iter % tempo < 400 /*&& iter%tempo >= 0*/) {
325 e2 = 0;
326 e1[0] = fabs(secondary_task_speed);
327 proj_e1 = task.secondaryTask(e1);
328 double frac = secondary_task_speed / proj_e1[0];
329 proj_e1 *= frac;
330 v_c += proj_e1;
331 if (iter == 199)
332 iter += 200; // This line is needed to make only an half turn // during the first cycle
333 }
334
335 if (iter % tempo < 600 && iter % tempo >= 400) {
336 e1 = 0;
337 e2[1] = fabs(secondary_task_speed);
338 proj_e2 = task.secondaryTask(e2);
339 double frac = secondary_task_speed / proj_e2[1];
340 proj_e2 *= frac;
341 v_c += proj_e2;
342 }
343
344 if (iter % tempo < 1000 && iter % tempo >= 600) {
345 e2 = 0;
346 e1[0] = -fabs(secondary_task_speed);
347 proj_e1 = task.secondaryTask(e1);
348 double frac = -secondary_task_speed / proj_e1[0];
349 proj_e1 *= frac;
350 v_c += proj_e1;
351 }
352
353 if (iter % tempo < 1200 && iter % tempo >= 1000) {
354 e1 = 0;
355 e2[1] = -fabs(secondary_task_speed);
356 proj_e2 = task.secondaryTask(e2);
357 double frac = -secondary_task_speed / proj_e2[1];
358 proj_e2 *= frac;
359 v_c += proj_e2;
360 }
361
362 robot.setVelocity(vpRobot::CAMERA_FRAME, v_c);
363
364 ss.str("");
365 ss << "Loop time: " << vpTime::measureTimeMs() - t_start << " ms";
366 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::red);
367 vpDisplay::displayText(I, 60, 20, "Secondary task started", vpColor::red);
369
371 if (vpDisplay::getClick(I, button, false)) {
372 final_quit = true;
373 }
374
375 iter++;
376 }
377
378 std::cout << "Stop the robot " << std::endl;
379 robot.setRobotState(vpRobot::STATE_STOP);
380
381 if (!final_quit) {
382 while (!final_quit) {
383 rs.acquire(I);
385
386 vpDisplay::displayText(I, 20, 20, "Click to quit the program.", vpColor::red);
387 vpDisplay::displayText(I, 40, 20, "Visual servo converged.", vpColor::red);
388
389 if (vpDisplay::getClick(I, false)) {
390 final_quit = true;
391 }
392
394 }
395 }
396 task.print();
397 }
398 catch (const vpException &e) {
399 std::cout << "ViSP exception: " << e.what() << std::endl;
400 std::cout << "Stop the robot " << std::endl;
401 robot.setRobotState(vpRobot::STATE_STOP);
402#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
403 if (display != nullptr) {
404 delete display;
405 }
406#endif
407 return EXIT_FAILURE;
408 }
409
410#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11)
411 if (display != nullptr) {
412 delete display;
413 }
414#endif
415 return EXIT_SUCCESS;
416}
417
418#else
419int main()
420{
421 std::cout << "You do not have an afma6 robot connected to your computer..." << std::endl;
422 return EXIT_SUCCESS;
423}
424
425#endif
Adaptive gain computation.
@ TOOL_INTEL_D435_CAMERA
Definition vpAfma6.h:129
Generic class defining intrinsic camera parameters.
@ perspectiveProjWithDistortion
Perspective projection with distortion model.
Implementation of column vector and the associated operations.
static const vpColor red
Definition vpColor.h:198
static const vpColor green
Definition vpColor.h:201
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)
Implementation of an homogeneous matrix and operations on such kind of matrices.
Definition of the vpImage class member functions.
Definition vpImage.h:131
static double rad(double deg)
Definition vpMath.h:129
static double deg(double rad)
Definition vpMath.h:119
@ RANGE_RESULT
Definition vpMeSite.h:85
Definition vpMe.h:143
void setPointsToTrack(const int &points_to_track)
Definition vpMe.h:431
void setRange(const unsigned int &range)
Definition vpMe.h:438
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
Definition vpMe.h:531
void setThreshold(const double &threshold)
Definition vpMe.h:489
void setSampleStep(const double &sample_step)
Definition vpMe.h:445
@ NORMALIZED_THRESHOLD
Definition vpMe.h:154
void acquire(vpImage< unsigned char > &grey, double *ts=nullptr)
bool open(const rs2::config &cfg=rs2::config())
Control of Irisa's gantry robot named Afma6.
@ CAMERA_FRAME
Definition vpRobot.h:81
@ STATE_VELOCITY_CONTROL
Initialize the velocity controller.
Definition vpRobot.h:64
@ STATE_STOP
Stops robot motion especially in velocity and acceleration control.
Definition vpRobot.h:63
@ EYEINHAND_CAMERA
Definition vpServo.h:176
@ PSEUDO_INVERSE
Definition vpServo.h:250
@ DESIRED
Definition vpServo.h:223
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()