1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Basic class used to make robot simulators.
33  *
34  * Authors:
35  * Nicolas Melchior
36  *
37  *****************************************************************************/
38 
39 #ifndef vpRobotWireFrameSimulator_HH
40 #define vpRobotWireFrameSimulator_HH
41 
42 /*!
43   \file vpRobotWireFrameSimulator.h
44   \brief Basic class used to make robot simulators.
45 */
46 
47 #include <visp3/core/vpConfig.h>
48 
49 #if defined(VISP_HAVE_MODULE_GUI) && ((defined(_WIN32) && !defined(WINRT_8_0)) || defined(VISP_HAVE_PTHREAD))
50 
51 #include <cmath>  // std::fabs
52 #include <limits> // numeric_limits
53 #if defined(_WIN32)
54 // Include WinSock2.h before windows.h to ensure that winsock.h is not
55 // included by windows.h since winsock.h and winsock2.h are incompatible
56 #include <WinSock2.h>
57 #include <windows.h>
58 #elif defined(VISP_HAVE_PTHREAD)
59 #include <pthread.h>
60 #endif
61 
62 #include <visp3/gui/vpDisplayD3D.h>
63 #include <visp3/gui/vpDisplayGDI.h>
64 #include <visp3/gui/vpDisplayGTK.h>
65 #include <visp3/gui/vpDisplayOpenCV.h>
66 #include <visp3/gui/vpDisplayX.h>
67 #include <visp3/robot/vpRobot.h>
68 #include <visp3/robot/vpRobotSimulator.h>
69 #include <visp3/robot/vpWireFrameSimulator.h>
70 
71 /*!
72   \class vpRobotWireFrameSimulator
73 
74   \ingroup group_robot_simu_gantry group_robot_simu_arm
75 
76   \brief This class aims to be a basis used to create all the
77   simulators of robots.
78 
79   Thus in this class you will find all the parameters and methods
80   which are necessary to create a simulator. Several methods are pure
81   virtual. In this case it means that they are specific to the each
82   robot, for example the computation of the geometrical model.
83 
84   \warning This class uses threading capabilities. Thus on Unix-like
85   platforms, the libpthread third-party library need to be
86   installed. On Windows, we use the native threading capabilities.
87 */
88 class VISP_EXPORT vpRobotWireFrameSimulator : protected vpWireFrameSimulator, public vpRobotSimulator
89 {
90 public:
91   vpImage<vpRGBa> I;
92 
93   typedef enum { MODEL_3D, MODEL_DH } vpDisplayRobotType;
94 
95 protected:
96   /*! cpu time at the begining of the robot's movement*/
97   double tcur;
98   /*! cpu time at the end of the last robot's movement*/
99   double tprev;
100 
101   /*! Contains the 3D model of the robot's arms*/
102   Bound_scene *robotArms;
103 
104   /*! Size of the fMi table*/
105   unsigned int size_fMi;
106   /*! Table containing all the homogeneous matrices between the reference
107   frame of the robot and the frames you used to compute the Denavit-Hartenberg
108   representation
109 
110   If you use a camera at the end of the effector, the last homogeneous matrix
111   has to be the one between the reference frame and the camera frame (fMc)*/
112   vpHomogeneousMatrix *fMi;
113 
114   /*! The articular coordinates*/
115   vpColVector artCoord;
116   /*! The articular velocity*/
117   vpColVector artVel;
118   /*! The velocity in the current frame (articular, camera or reference)*/
119   vpColVector velocity;
120 
121 #if defined(_WIN32)
122   HANDLE hThread;
123   HANDLE mutex_fMi;
124   HANDLE mutex_artVel;
125   HANDLE mutex_artCoord;
126   HANDLE mutex_velocity;
127   HANDLE mutex_display;
128 #elif defined(VISP_HAVE_PTHREAD)
129   pthread_t thread;
130   pthread_attr_t attr;
131   pthread_mutex_t mutex_fMi;
132   pthread_mutex_t mutex_artVel;
133   pthread_mutex_t mutex_artCoord;
134   pthread_mutex_t mutex_velocity;
135   pthread_mutex_t mutex_display;
136 #endif
137 
138   bool displayBusy;
139 
140   /*! True if the robot has to be stopped*/
141   bool robotStop;
142   /*! True if one of the joint reach the limit*/
143   bool jointLimit;
144   /*! Index of the joint which is in limit*/
145   unsigned int jointLimitArt;
146   /*! True if the singularity are automatically managed */
147   bool singularityManagement;
148 
149   /*! External camera parameters*/
150   vpCameraParameters cameraParam;
151 
152 #if defined VISP_HAVE_X11
153   vpDisplayX display;
154 #elif defined VISP_HAVE_GDI
155   vpDisplayGDI display;
156 #elif defined VISP_HAVE_OPENCV
157   vpDisplayOpenCV display;
158 #elif defined VISP_HAVE_D3D9
159   vpDisplayD3D display;
160 #elif defined VISP_HAVE_GTK
161   vpDisplayGTK display;
162 #endif
163 
164   vpDisplayRobotType displayType;
165 
166   bool displayAllowed;
167   //! Flag used to force the sampling time in the thread computing the robot's
168   //! displacement to a constant value (\e samplingTime). It may be useful if
169   //! the main thread (computing the features) is very time consumming. False
170   //! by default.
171   bool constantSamplingTimeMode;
172 
173   //! Flag used to specify to the thread managing the robot displacements that
174   //! the setVelocity() method has been called.
175   bool setVelocityCalled;
176 
177   bool verbose_;
178 
179   // private:
180   //#ifndef DOXYGEN_SHOULD_SKIP_THIS
181   //    vpRobotWireFrameSimulator(const vpRobotWireFrameSimulator &)
182   //      : vpWireFrameSimulator(), vpRobotSimulator(),
183   //        I(), tcur(0), tprev(0), robotArms(NULL), size_fMi(8), fMi(NULL),
184   //        artCoord(), artVel(), velocity(),
185   //    #if defined(_WIN32)
186   //    #elif defined(VISP_HAVE_PTHREAD)
187   //        thread(), attr(),
188   //    #endif
189   //        mutex_fMi(), mutex_artVel(), mutex_artCoord(), mutex_velocity(),
190   //        mutex_display(), displayBusy(false), robotStop(false),
191   //        jointLimit(false), jointLimitArt(false),
192   //        singularityManagement(true), cameraParam(),
193   //    #if defined(VISP_HAVE_DISPLAY)
194   //        display(),
195   //    #endif
196   //        displayType(MODEL_3D), displayAllowed(true),
197   //        constantSamplingTimeMode(false), setVelocityCalled(false),
198   //        verbose_(false)
199   //    {
200   //      throw vpException(vpException::functionNotImplementedError, "Not
201   //      implemented!");
202   //    }
203   //    vpRobotWireFrameSimulator &operator=(const vpRobotWireFrameSimulator
204   //    &){
205   //      throw vpException(vpException::functionNotImplementedError, "Not
206   //      implemented!"); return *this;
207   //    }
208   //#endif
209 
210 public:
211   vpRobotWireFrameSimulator();
212   explicit vpRobotWireFrameSimulator(bool display);
213   virtual ~vpRobotWireFrameSimulator();
214 
215   /** @name Inherited functionalities from vpRobotWireFrameSimulator */
216   //@{
217   /*!
218     Get the parameters of the virtual external camera.
219 
220     \return It returns the camera parameters.
221   */
getExternalCameraParameters()222   vpCameraParameters getExternalCameraParameters() const
223   {
224     // if(px_ext != 1 && py_ext != 1)
225     // we assume px_ext and py_ext > 0
226     if ((std::fabs(px_ext - 1.) > vpMath::maximum(px_ext, 1.) * std::numeric_limits<double>::epsilon()) &&
227         (std::fabs(py_ext - 1) > vpMath::maximum(py_ext, 1.) * std::numeric_limits<double>::epsilon()))
228       return vpCameraParameters(px_ext, py_ext, I.getWidth() / 2, I.getHeight() / 2);
229     else {
230       unsigned int size = vpMath::minimum(I.getWidth(), I.getHeight()) / 2;
231       return vpCameraParameters(size, size, I.getWidth() / 2, I.getHeight() / 2);
232     }
233   }
234   /*!
235     Get the external camera's position relative to the the world reference
236     frame.
237 
238     \return the main external camera position relative to the the world
239     reference frame.
240   */
getExternalCameraPosition()241   vpHomogeneousMatrix getExternalCameraPosition() const
242   {
243     return this->vpWireFrameSimulator::getExternalCameraPosition();
244   }
245 
246   void getInternalView(vpImage<vpRGBa> &I);
247   void getInternalView(vpImage<unsigned char> &I);
248 
249   vpHomogeneousMatrix get_cMo();
250   /*!
251     Get the pose between the object and the fixed world frame.
252 
253     \return The pose between the object and the fixed world frame.
254   */
get_fMo()255   vpHomogeneousMatrix get_fMo() const { return fMo; }
256 
257   /* Display functions */
258   void initScene(const vpSceneObject &obj, const vpSceneDesiredObject &desiredObject);
259   void initScene(const char *obj, const char *desiredObject);
260   void initScene(const vpSceneObject &obj);
261   void initScene(const char *obj);
262 
263   /*!
264     Set the color used to display the camera in the external view.
265 
266     \param col : The desired color.
267   */
setCameraColor(const vpColor & col)268   void setCameraColor(const vpColor &col) { camColor = col; }
269 
270   /*!
271     Set the flag used to force the sampling time in the thread computing the
272     robot's displacement to a constant value; see setSamplingTime(). It may be
273     useful if the main thread (computing the features) is very time consuming.
274     False by default.
275 
276     \param _constantSamplingTimeMode : The new value of the
277     constantSamplingTimeMode flag.
278   */
setConstantSamplingTimeMode(const bool _constantSamplingTimeMode)279   inline void setConstantSamplingTimeMode(const bool _constantSamplingTimeMode)
280   {
281     constantSamplingTimeMode = _constantSamplingTimeMode;
282   }
283 
284   /*!
285     Set the color used to display the object at the current position in the
286     robot's camera view.
287 
288     \param col : The desired color.
289   */
setCurrentViewColor(const vpColor & col)290   void setCurrentViewColor(const vpColor &col) { curColor = col; }
291 
292   /*!
293     Set the color used to display the object at the desired position in the
294     robot's camera view.
295 
296     \param col : The desired color.
297   */
setDesiredViewColor(const vpColor & col)298   void setDesiredViewColor(const vpColor &col) { desColor = col; }
299 
300   /*!
301     Set the desired position of the robot's camera relative to the object.
302 
303     \param cdMo_ : The desired pose of the camera.
304   */
setDesiredCameraPosition(const vpHomogeneousMatrix & cdMo_)305   void setDesiredCameraPosition(const vpHomogeneousMatrix &cdMo_)
306   {
307     this->vpWireFrameSimulator::setDesiredCameraPosition(cdMo_);
308   }
309 
310   /*!
311     Set the way to draw the robot. Depending on what you choose you can
312     display a 3D wireframe model or a set of lines linking the frames used to
313     compute the geometrical model.
314 
315     \param dispType : Type of display. Can be MODEL_3D or MODEL_DH.
316   */
setDisplayRobotType(const vpDisplayRobotType dispType)317   inline void setDisplayRobotType(const vpDisplayRobotType dispType) { displayType = dispType; }
318   /*!
319     Set the external camera point of view.
320 
321     \param camMf_ : The pose of the external camera relative to the world
322     reference frame.
323   */
setExternalCameraPosition(const vpHomogeneousMatrix & camMf_)324   void setExternalCameraPosition(const vpHomogeneousMatrix &camMf_)
325   {
326     this->vpWireFrameSimulator::setExternalCameraPosition(camMf_);
327   }
328   /*!
329     Specify the thickness of the graphics drawings.
330     */
setGraphicsThickness(unsigned int thickness)331   void setGraphicsThickness(unsigned int thickness) { this->thickness_ = thickness; }
332 
333   /*!
334     Set the sampling time.
335 
336     \param delta_t : Sampling time in second used to compute the robot
337     displacement from the velocity applied to the robot during this time.
338 
339     Since the wireframe simulator is threaded, the sampling time is set to
340     vpTime::getMinTimeForUsleepCall() / 1000 seconds.
341 
342   */
setSamplingTime(const double & delta_t)343   inline void setSamplingTime(const double &delta_t)
344   {
345     if (delta_t < static_cast<float>(vpTime::getMinTimeForUsleepCall() * 1e-3)) {
346       this->delta_t_ = static_cast<float>(vpTime::getMinTimeForUsleepCall() * 1e-3);
347     } else {
348       this->delta_t_ = delta_t;
349     }
350   }
351   /*! Set the parameter which enable or disable the singularity mangement */
setSingularityManagement(bool sm)352   void setSingularityManagement(bool sm) { singularityManagement = sm; }
353 
354   /*!
355     Activates extra printings when the robot reaches joint limits...
356     */
setVerbose(bool verbose)357   void setVerbose(bool verbose) { this->verbose_ = verbose; }
358 
359   /*!
360     Set the pose between the object and the fixed world frame.
361 
362     \param fMo_ : The pose between the object and the fixed world frame.
363   */
set_fMo(const vpHomogeneousMatrix & fMo_)364   void set_fMo(const vpHomogeneousMatrix &fMo_) { this->fMo = fMo_; }
365   //@}
366 
367 protected:
368 /** @name Protected Member Functions Inherited from vpRobotWireFrameSimulator
369  */
370 //@{
371 /*!
372   Function used to launch the thread which moves the robot.
373 */
374 #if defined(_WIN32)
launcher(LPVOID lpParam)375   static DWORD WINAPI launcher(LPVOID lpParam)
376   {
377     (static_cast<vpRobotWireFrameSimulator *>(lpParam))->updateArticularPosition();
378     return 0;
379   }
380 #elif defined(VISP_HAVE_PTHREAD)
381   static void *launcher(void *arg)
382   {
383     (reinterpret_cast<vpRobotWireFrameSimulator *>(arg))->updateArticularPosition();
384     // pthread_exit((void*) 0);
385     return NULL;
386   }
387 #endif
388 
389   /* Robot functions */
init()390   void init() { ; }
391   /*! Method lauched by the thread to compute the position of the robot in the
392    * articular frame. */
393   virtual void updateArticularPosition() = 0;
394   /*! Method used to check if the robot reached a joint limit. */
395   virtual int isInJointLimit() = 0;
396   /*! Compute the articular velocity relative to the velocity in another
397    * frame. */
398   virtual void computeArticularVelocity() = 0;
399 
400   /* Display functions */
initDisplay()401   void initDisplay() { ; }
402   virtual void initArms() = 0;
403 
404 #if defined(_WIN32)
get_artCoord()405   vpColVector get_artCoord() const
406   {
407 #if defined(WINRT_8_1)
408     WaitForSingleObjectEx(mutex_artCoord, INFINITE, FALSE);
409 #else // pure win32
410     WaitForSingleObject(mutex_artCoord, INFINITE);
411 #endif
412     vpColVector artCoordTmp(6);
413     artCoordTmp = artCoord;
414     ReleaseMutex(mutex_artCoord);
415     return artCoordTmp;
416   }
set_artCoord(const vpColVector & coord)417   void set_artCoord(const vpColVector &coord)
418   {
419 #if defined(WINRT_8_1)
420     WaitForSingleObjectEx(mutex_artCoord, INFINITE, FALSE);
421 #else // pure win32
422     WaitForSingleObject(mutex_artCoord, INFINITE);
423 #endif
424     artCoord = coord;
425     ReleaseMutex(mutex_artCoord);
426   }
427 
get_artVel()428   vpColVector get_artVel() const
429   {
430 #if defined(WINRT_8_1)
431     WaitForSingleObjectEx(mutex_artVel, INFINITE, FALSE);
432 #else // pure win32
433     WaitForSingleObject(mutex_artVel, INFINITE);
434 #endif
435     vpColVector artVelTmp(artVel);
436     ReleaseMutex(mutex_artVel);
437     return artVelTmp;
438   }
set_artVel(const vpColVector & vel)439   void set_artVel(const vpColVector &vel)
440   {
441 #if defined(WINRT_8_1)
442     WaitForSingleObjectEx(mutex_artVel, INFINITE, FALSE);
443 #else // pure win32
444     WaitForSingleObject(mutex_artVel, INFINITE);
445 #endif
446     artVel = vel;
447     ReleaseMutex(mutex_artVel);
448   }
449 
get_velocity()450   vpColVector get_velocity()
451   {
452 #if defined(WINRT_8_1)
453     WaitForSingleObjectEx(mutex_velocity, INFINITE, FALSE);
454 #else // pure win32
455     WaitForSingleObject(mutex_velocity, INFINITE);
456 #endif
457     vpColVector velocityTmp = velocity;
458     ReleaseMutex(mutex_velocity);
459     return velocityTmp;
460   }
set_velocity(const vpColVector & vel)461   void set_velocity(const vpColVector &vel)
462   {
463 #if defined(WINRT_8_1)
464     WaitForSingleObjectEx(mutex_velocity, INFINITE, FALSE);
465 #else // pure win32
466     WaitForSingleObject(mutex_velocity, INFINITE);
467 #endif
468     velocity = vel;
469     ReleaseMutex(mutex_velocity);
470   }
471 
set_displayBusy(const bool & status)472   void set_displayBusy(const bool &status)
473   {
474 #if defined(WINRT_8_1)
475     WaitForSingleObjectEx(mutex_display, INFINITE, FALSE);
476 #else // pure win32
477     WaitForSingleObject(mutex_display, INFINITE);
478 #endif
479     displayBusy = status;
480     ReleaseMutex(mutex_display);
481   }
get_displayBusy()482   bool get_displayBusy()
483   {
484 #if defined(WINRT_8_1)
485     WaitForSingleObjectEx(mutex_display, INFINITE, FALSE);
486 #else // pure win32
487     WaitForSingleObject(mutex_display, INFINITE);
488 #endif
489     bool status = displayBusy;
490     if (!displayBusy)
491       displayBusy = true;
492     ReleaseMutex(mutex_display);
493     return status;
494   }
495 
496 #elif defined(VISP_HAVE_PTHREAD)
get_artCoord()497   vpColVector get_artCoord()
498   {
499     pthread_mutex_lock(&mutex_artCoord);
500     vpColVector artCoordTmp(6);
501     artCoordTmp = artCoord;
502     pthread_mutex_unlock(&mutex_artCoord);
503     return artCoordTmp;
504   }
set_artCoord(const vpColVector & coord)505   void set_artCoord(const vpColVector &coord)
506   {
507     pthread_mutex_lock(&mutex_artCoord);
508     artCoord = coord;
509     pthread_mutex_unlock(&mutex_artCoord);
510   }
511 
get_artVel()512   vpColVector get_artVel()
513   {
514     pthread_mutex_lock(&mutex_artVel);
515     vpColVector artVelTmp(artVel);
516     pthread_mutex_unlock(&mutex_artVel);
517     return artVelTmp;
518   }
set_artVel(const vpColVector & vel)519   void set_artVel(const vpColVector &vel)
520   {
521     pthread_mutex_lock(&mutex_artVel);
522     artVel = vel;
523     pthread_mutex_unlock(&mutex_artVel);
524   }
525 
get_velocity()526   vpColVector get_velocity()
527   {
528     pthread_mutex_lock(&mutex_velocity);
529     vpColVector velocityTmp = velocity;
530     pthread_mutex_unlock(&mutex_velocity);
531     return velocityTmp;
532   }
set_velocity(const vpColVector & vel)533   void set_velocity(const vpColVector &vel)
534   {
535     pthread_mutex_lock(&mutex_velocity);
536     velocity = vel;
537     pthread_mutex_unlock(&mutex_velocity);
538   }
539 
set_displayBusy(const bool & status)540   void set_displayBusy(const bool &status)
541   {
542     pthread_mutex_lock(&mutex_display);
543     displayBusy = status;
544     pthread_mutex_unlock(&mutex_display);
545   }
get_displayBusy()546   bool get_displayBusy()
547   {
548     pthread_mutex_lock(&mutex_display);
549     bool status = displayBusy;
550     if (!displayBusy)
551       displayBusy = true;
552     pthread_mutex_unlock(&mutex_display);
553     return status;
554   }
555 #endif
556 
557   /*! Get a table of poses between the reference frame and the frames you used
558    * to compute the Denavit-Hartenberg representation */
559   virtual void get_fMi(vpHomogeneousMatrix *fMit) = 0;
560   //@}
561 };
562 
563 #endif
564 #endif
565