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: Class which enables to project an image in the 3D space
32 * and get the view of a virtual camera.
33 *
34 * Authors:
35 * Fabien Spindler
36 *
37 *****************************************************************************/
38
39 /*!
40 \file vpVirtuose.cpp
41 \brief Wrapper over Haption Virtuose SDK to control haptic devices.
42 */
43
44 #include <visp3/core/vpException.h>
45 #include <visp3/robot/vpVirtuose.h>
46
47 #ifdef VISP_HAVE_VIRTUOSE
48
49 /*!
50 * Default constructor.
51 * Set command type to virtual mechanism by default (impedance mode).
52 * Authorize indexing on all movements by default.
53 */
vpVirtuose()54 vpVirtuose::vpVirtuose()
55 : m_virtContext(NULL), m_ip_port("localhost#5000"), m_verbose(false), m_apiMajorVersion(0), m_apiMinorVersion(0),
56 m_ctrlMajorVersion(0), m_ctrlMinorVersion(0), m_typeCommand(COMMAND_TYPE_IMPEDANCE), m_indexType(INDEXING_ALL),
57 m_is_init(false), m_period(0.001f), m_njoints(6)
58 {
59 virtAPIVersion(&m_apiMajorVersion, &m_apiMinorVersion);
60 std::cout << "API version: " << m_apiMajorVersion << "." << m_apiMinorVersion << std::endl;
61 }
62
63 /*!
64 * Delete the VirtContext object.
65 */
close()66 void vpVirtuose::close()
67 {
68 if (m_virtContext != NULL) {
69 virtClose(m_virtContext);
70 m_virtContext = NULL;
71 }
72 }
73
74 /*!
75 * Default destructor that delete the VirtContext object.
76 */
~vpVirtuose()77 vpVirtuose::~vpVirtuose()
78 {
79 close();
80 }
81
82 /*!
83 * Set haptic device ip address and communication port.
84 * \param[in] ip: Host IP address. Default value set in constructor is "localhost".
85 * \param[in] port: Host communication port. Default value set in constructor is 5000.
86 */
setIpAddressAndPort(const std::string & ip,int port)87 void vpVirtuose::setIpAddressAndPort(const std::string &ip, int port)
88 {
89 std::stringstream ss;
90 ss << ip << "#" << port;
91
92 m_ip_port = ss.str();
93 }
94
95 /*!
96 * Add a force to be applied to the virtuose (impedance effort).
97 * This function works in every mode.
98 * \param force : Is 6 component dynamic tensor (three forces and three
99 * torques) wrt virtuose end-effector and is expressed in the coordinates of
100 * the base frame.
101 */
addForce(vpColVector & force)102 void vpVirtuose::addForce(vpColVector &force)
103 {
104 if (force.size() != 6) {
105 throw(vpException(vpException::dimensionError,
106 "Cannot apply a force feedback (dim %d) to the haptic "
107 "device that is not 6-dimension",
108 force.size()));
109 }
110
111 init();
112
113 float virtforce[6];
114 for (unsigned int i = 0; i < 6; i++)
115 virtforce[i] = (float)force[i];
116
117 if (virtAddForce(m_virtContext, virtforce)) {
118 int err = virtGetErrorCode(m_virtContext);
119 throw(vpException(vpException::fatalError, "Error calling virtAddForce: error code %d", err));
120 }
121 }
122
123 /*!
124 * Activate or desactivate force feedback.
125 * \param enable : 1 to activate (system's default value), 0 to desactivate.
126 */
enableForceFeedback(int enable)127 void vpVirtuose::enableForceFeedback(int enable)
128 {
129 init();
130
131 if (virtEnableForceFeedback(m_virtContext, enable)) {
132 int err = virtGetErrorCode(m_virtContext);
133 throw(vpException(vpException::fatalError, "Error calling virtEnableForceFeedback(): error code %d", err));
134 }
135 }
136
137 /*!
138 * Return the 6 joint values of the virtuose.
139 */
getArticularPosition() const140 vpColVector vpVirtuose::getArticularPosition() const
141 {
142 if (!m_is_init) {
143 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
144 }
145
146
147 float articular_position_[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
148
149 if (virtGetArticularPosition(m_virtContext, articular_position_)) {
150 int err = virtGetErrorCode(m_virtContext);
151 throw(vpException(vpException::fatalError, "Error calling virtGetArticularPosition(): error code %d", err));
152 }
153
154 vpColVector articularPosition(m_njoints, 0);
155 for (unsigned int i = 0; i < m_njoints; i++)
156 articularPosition[i] = articular_position_[i];
157
158 return articularPosition;
159 }
160
161 /*!
162 * Return the 6 joint velocities of the virtuose.
163 */
getArticularVelocity() const164 vpColVector vpVirtuose::getArticularVelocity() const
165 {
166 if (!m_is_init) {
167 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
168 }
169
170 float articular_velocity_[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
171
172 if (virtGetArticularSpeed(m_virtContext, articular_velocity_)) {
173 int err = virtGetErrorCode(m_virtContext);
174 throw(vpException(vpException::fatalError, "Error calling virtGetArticularSpeed: error code %d", err));
175 }
176
177 vpColVector articularVelocity(m_njoints, 0);
178
179 for (unsigned int i = 0; i < m_njoints; i++)
180 articularVelocity[i] = articular_velocity_[i];
181
182 return articularVelocity;
183 }
184
185 /*!
186 * Return the indexed position of the end-effector, expressed in the
187 * coordinates of the environment reference frame. With respect to the
188 * function getPosition(), getAvatarPosition() takes into account current
189 * offsets (indexing) and motor scale factors. \sa getPosition(),
190 * getPhysicalPosition()
191 */
getAvatarPosition() const192 vpPoseVector vpVirtuose::getAvatarPosition() const
193 {
194 if (!m_is_init) {
195 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
196 }
197
198 float position_[7];
199 vpPoseVector position;
200 vpTranslationVector translation;
201 vpQuaternionVector quaternion;
202
203 if (virtGetAvatarPosition(m_virtContext, position_)) {
204 int err = virtGetErrorCode(m_virtContext);
205 throw(vpException(vpException::fatalError, "Error calling virtGetAvatarPosition: error code %d", err));
206 } else {
207 for (int i = 0; i < 3; i++)
208 translation[i] = position_[i];
209 for (int i = 0; i < 4; i++)
210 quaternion[i] = position_[3 + i];
211
212 vpThetaUVector thetau(quaternion);
213
214 position.buildFrom(translation, thetau);
215
216 return position;
217 }
218 }
219
220 /*!
221 * Return the current position of the base frame
222 * with respect to the observation reference frame.
223 *
224 * \sa setBaseFrame(), getObservationFrame()
225 */
getBaseFrame() const226 vpPoseVector vpVirtuose::getBaseFrame() const
227 {
228 if (!m_is_init) {
229 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
230 }
231
232 vpPoseVector position;
233 float position_[7];
234 vpTranslationVector translation;
235 vpQuaternionVector quaternion;
236
237 if (virtGetBaseFrame(m_virtContext, position_)) {
238 int err = virtGetErrorCode(m_virtContext);
239 throw(vpException(vpException::fatalError, "Error calling virtGetBaseFrame: error code %d", err));
240 } else {
241 for (int i = 0; i < 3; i++)
242 translation[i] = position_[i];
243 for (int i = 0; i < 4; i++)
244 quaternion[i] = position_[3 + i];
245
246 vpThetaUVector thetau(quaternion);
247
248 position.buildFrom(translation, thetau);
249
250 return position;
251 }
252 }
253
254 /*!
255 * Return the current command type.
256 */
getCommandType() const257 VirtCommandType vpVirtuose::getCommandType() const
258 {
259 if (!m_is_init) {
260 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
261 }
262
263 VirtCommandType type;
264
265 if (virtGetCommandType(m_virtContext, &type)) {
266 int err = virtGetErrorCode(m_virtContext);
267 throw(vpException(vpException::fatalError, "Error calling virtGetCommandType: error code %d", err));
268 }
269 return type;
270 }
271
272 /*!
273 * Return the status of DeadMan sensor : true if the sensor is ON (a user is
274 * holding the handle) and false if the sensor is OFF (no user detected).
275 */
getDeadMan() const276 bool vpVirtuose::getDeadMan() const
277 {
278 if (!m_is_init) {
279 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
280 }
281
282 int deadman;
283 if (virtGetDeadMan(m_virtContext, &deadman)) {
284 int err = virtGetErrorCode(m_virtContext);
285 throw(vpException(vpException::fatalError, "Error calling virtGetDeadMan: error code %d", err));
286 }
287 return (deadman ? true : false);
288 }
289
290 /*!
291 * Return the status of the emergency stop button : true if the system is
292 * operational (button correctly plugged and not triggered) and false if the
293 * system is not operational (button not plugged or triggered).
294 */
getEmergencyStop() const295 bool vpVirtuose::getEmergencyStop() const
296 {
297 if (!m_is_init) {
298 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
299 }
300
301 int emergencyStop;
302 if (virtGetEmergencyStop(m_virtContext, &emergencyStop)) {
303 int err = virtGetErrorCode(m_virtContext);
304 throw(vpException(vpException::fatalError, "Error calling virtGetEmergencyStop: error code %d", err));
305 }
306 return (emergencyStop ? true : false);
307 }
308
309 /*!
310 * Return the 6-dimension force tensor to be applied to the object attached to
311 * the Virtuose, allowing the dynamic simulation of the scene.
312 */
getForce() const313 vpColVector vpVirtuose::getForce() const
314 {
315 if (!m_is_init) {
316 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
317 }
318
319 vpColVector force(6, 0);
320 float force_[6];
321 if (virtGetForce(m_virtContext, force_)) {
322 int err = virtGetErrorCode(m_virtContext);
323 throw(vpException(vpException::fatalError, "Error calling virtGetForce: error code %d", err));
324 }
325
326 for (unsigned int i = 0; i < 6; i++)
327 force[i] = force_[i];
328 return force;
329 }
330
331 /*!
332 Return the handler used to communicate with the device.
333 This function could be used to access to a functionality that is not
334 implemented in vpVirtuose class.
335
336 The following sample code shows how to use this function to get the
337 device joint positions. This functionality is already implemented
338 in getArticularPosition().
339 \code
340 #include <visp3/robot/vpVirtuose.h>
341
342 int main()
343 {
344 vpVirtuose virtuose;
345
346 virtuose.init();
347
348 VirtContext handler = virtuose.getHandler();
349 float q[6];
350 if (virtGetArticularPosition(handler, q)) { // Use the handler to access to Haption API directly
351 std::cout << "Cannot get articular position" << std::endl;
352 }
353 std::cout << "Joint position: ";
354 for (unsigned int i=0; i<6; i++)
355 std::cout << q[i] << " ";
356 std::cout << std::endl;
357 }
358 \endcode
359
360 \sa getArticularPosition()
361
362 */
getHandler()363 VirtContext vpVirtuose::getHandler() { return m_virtContext; }
364
365 /*!
366 Get device number of joints.
367
368 \return The number of joints of the device. Sould be 6 for Virtuose, 9 for the glove fingers.
369 */
getJointsNumber() const370 unsigned int vpVirtuose::getJointsNumber() const
371 {
372 if (!m_is_init) {
373 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
374 }
375
376 return m_njoints;
377 }
378
379
380 /*!
381 * Return the cartesian current position of the observation reference frame
382 * with respect to the environment reference frame.
383 *
384 * \sa setObservationFrame(), getBaseFrame()
385 */
getObservationFrame() const386 vpPoseVector vpVirtuose::getObservationFrame() const
387 {
388 if (!m_is_init) {
389 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
390 }
391
392 vpPoseVector position;
393 float position_[7];
394 vpTranslationVector translation;
395 vpQuaternionVector quaternion;
396
397 if (virtGetObservationFrame(m_virtContext, position_)) {
398 int err = virtGetErrorCode(m_virtContext);
399 throw(vpException(vpException::fatalError, "Error calling virtGetObservationFrame: error code %d", err));
400 } else {
401 for (int i = 0; i < 3; i++)
402 translation[i] = position_[i];
403 for (int i = 0; i < 4; i++)
404 quaternion[i] = position_[3 + i];
405
406 vpThetaUVector thetau(quaternion);
407
408 position.buildFrom(translation, thetau);
409 }
410 return position;
411 }
412
413 /*!
414 * Return the cartesian physical position of the Virtuose expressed in the
415 * coordinates of the base reference frame.
416 *
417 * \sa getAvatarPosition(), getPosition()
418 */
getPhysicalPosition() const419 vpPoseVector vpVirtuose::getPhysicalPosition() const
420 {
421 if (!m_is_init) {
422 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
423 }
424
425 vpPoseVector position;
426 float position_[7];
427 vpTranslationVector translation;
428 vpQuaternionVector quaternion;
429
430 if (virtGetPhysicalPosition(m_virtContext, position_)) {
431 int err = virtGetErrorCode(m_virtContext);
432 throw(vpException(vpException::fatalError, "Error calling virtGetPhysicalPosition: error code %d", err));
433 } else {
434 for (int i = 0; i < 3; i++)
435 translation[i] = position_[i];
436 for (int i = 0; i < 4; i++)
437 quaternion[i] = position_[3 + i];
438
439 vpThetaUVector thetau(quaternion);
440
441 position.buildFrom(translation, thetau);
442 }
443 return position;
444 }
445
446 /*!
447 * Return the physical cartesian velocity twist of the Virtuose expressed in
448 * the coordinates of the base reference frame. \return A 6-dimension velocity
449 * twist with 3 translation velocities and 3 rotation velocities. \sa
450 * getVelocity()
451 */
getPhysicalVelocity() const452 vpColVector vpVirtuose::getPhysicalVelocity() const
453 {
454 if (!m_is_init) {
455 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
456 }
457
458 vpColVector vel(6, 0);
459 float speed[6];
460 if (virtGetPhysicalSpeed(m_virtContext, speed)) {
461 int err = virtGetErrorCode(m_virtContext);
462 throw(vpException(vpException::fatalError, "Error calling virtGetPhysicalSpeed: error code %s",
463 virtGetErrorMessage(err)));
464 }
465 for (unsigned int i = 0; i < 6; i++)
466 vel[i] = speed[i];
467 return vel;
468 }
469
470 /*!
471 * Return the cartesian position of the virtuose (or the object attached to
472 * it, if any) expressed in the coordinates of the environment reference
473 * frame. \sa getAvatarPosition(), getPhysicalPosition()
474 */
getPosition() const475 vpPoseVector vpVirtuose::getPosition() const
476 {
477 if (!m_is_init) {
478 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
479 }
480
481 vpPoseVector position;
482 float position_[7];
483 vpTranslationVector translation;
484 vpQuaternionVector quaternion;
485
486 if (virtGetPosition(m_virtContext, position_)) {
487 int err = virtGetErrorCode(m_virtContext);
488 throw(vpException(vpException::fatalError, "Error calling virtGetPosition: error code %d", err));
489 } else {
490 for (int i = 0; i < 3; i++)
491 translation[i] = position_[i];
492 for (int i = 0; i < 4; i++)
493 quaternion[i] = position_[3 + i];
494
495 vpThetaUVector thetau(quaternion);
496
497 position.buildFrom(translation, thetau);
498 }
499 return position;
500 }
501
502 /*!
503 * Return status of the motors : true if motors are ON, false otherwise.
504 */
getPower() const505 bool vpVirtuose::getPower() const
506 {
507 if (!m_is_init) {
508 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
509 }
510
511 int power;
512 virtGetPowerOn(m_virtContext, &power);
513 return (power ? true : false);
514 }
515
516 /*!
517 * Return the cartesian velocity twist of the virtuose (or the object attached
518 * to it, if any) expressed in the coordinates of the environment reference
519 * frame. \return A 6-dimension velocity twist with 3 translation velocities
520 * and 3 rotation velocities. \sa getPhysicalVelocity()
521 */
getVelocity() const522 vpColVector vpVirtuose::getVelocity() const
523 {
524 if (!m_is_init) {
525 throw(vpException(vpException::fatalError, "Device not initialized. Call init()."));
526 }
527
528 vpColVector vel(6, 0);
529 float speed[6];
530 if (virtGetSpeed(m_virtContext, speed)) {
531 int err = virtGetErrorCode(m_virtContext);
532 throw(vpException(vpException::fatalError, "Cannot get haptic device velocity: %s", virtGetErrorMessage(err)));
533 }
534 for (unsigned int i = 0; i < 6; i++)
535 vel[i] = speed[i];
536 return vel;
537 }
538
539 /*!
540 * Initialize virtuose device opening the connection to the device and setting
541 * the default command type. If the device is already initialized, a call to
542 * init() does nothing.
543 */
init()544 void vpVirtuose::init()
545 {
546 if (!m_is_init) {
547 m_virtContext = virtOpen(m_ip_port.c_str());
548
549 if (m_virtContext == NULL) {
550 int err = virtGetErrorCode(m_virtContext);
551 throw(vpException(vpException::fatalError, "Cannot open communication with haptic device using %s: %s. Check ip and port values",
552 m_ip_port.c_str(), virtGetErrorMessage(err)));
553 }
554
555 if (virtGetControlerVersion(m_virtContext, &m_ctrlMajorVersion, &m_ctrlMinorVersion)) {
556 int err = virtGetErrorCode(m_virtContext);
557 throw(vpException(vpException::fatalError, "Cannot get haptic device controller version: %s",
558 virtGetErrorMessage(err)));
559 }
560
561 if (m_verbose) {
562 std::cout << "Controller version: " << m_ctrlMajorVersion << "." << m_ctrlMinorVersion << std::endl;
563 }
564
565 if (virtSetCommandType(m_virtContext, m_typeCommand)) {
566 int err = virtGetErrorCode(m_virtContext);
567 throw(
568 vpException(vpException::fatalError, "Cannot set haptic device command type: %s", virtGetErrorMessage(err)));
569 }
570
571 if (virtSetTimeStep(m_virtContext, m_period)) {
572 int err = virtGetErrorCode(m_virtContext);
573 throw(vpException(vpException::fatalError, "Error calling virtSetTimeStep: error code %d", err));
574 }
575
576 // Update number of joints
577 float articular_position_[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
578
579 if (virtGetArticularPosition(m_virtContext, articular_position_)) {
580 int err = virtGetErrorCode(m_virtContext);
581 throw(vpException(vpException::fatalError, "Error calling virtGetArticularPosition() in int(): error code %d", err));
582 }
583
584 m_njoints = 6; // At least 6 joints
585 for (unsigned int i=m_njoints; i < 20; i++) {
586 m_njoints = i;
587 if (std::fabs(articular_position_[i]) <= std::numeric_limits<float>::epsilon()) {
588 break;
589 }
590 }
591
592 m_is_init = true;
593 }
594 }
595
596 /*!
597 * Send a command of articular force to the Virtuose.
598 * setArticularForce() only works in mode COMMAND_TYPE_ARTICULAR_IMPEDANCE, to
599 * be set with setCommandType().
600 *
601 * \param articularForce : Six dimension torque vector.
602 */
setArticularForce(const vpColVector & articularForce)603 void vpVirtuose::setArticularForce(const vpColVector &articularForce)
604 {
605 init();
606
607 if (articularForce.size() != m_njoints) {
608 throw(vpException(vpException::dimensionError,
609 "Cannot apply an articular force feedback (dim %d) to "
610 "the haptic device that is not 6-dimension",
611 articularForce.size()));
612 }
613
614 float *articular_force = new float [m_njoints];
615 for (unsigned int i = 0; i < m_njoints; i++)
616 articular_force[i] = (float)articularForce[i];
617
618 if (virtSetArticularForce(m_virtContext, articular_force)) {
619 delete[] articular_force;
620 int err = virtGetErrorCode(m_virtContext);
621 throw(vpException(vpException::fatalError, "Error calling virtSetArticularForce: error code %d", err));
622 }
623
624 delete [] articular_force;
625 }
626
627 /*!
628 * Send a command of articular (joint) position to the virtuose.
629 * This function works only in COMMAND_TYPE_ARTICULAR mode, to be set with
630 * setCommandType().
631 *
632 * \param articularPosition : Six dimension joint position vector.
633 */
setArticularPosition(const vpColVector & articularPosition)634 void vpVirtuose::setArticularPosition(const vpColVector &articularPosition)
635 {
636 init();
637
638 if (articularPosition.size() != m_njoints) {
639 throw(vpException(vpException::dimensionError,
640 "Cannot send an articular position command (dim %d) to "
641 "the haptic device that is not %d-dimension",
642 m_njoints, articularPosition.size()));
643 }
644
645 float *articular_position = new float[m_njoints];
646 for (unsigned int i = 0; i < m_njoints; i++)
647 articular_position[i] = (float)articularPosition[i];
648
649 if (virtSetArticularPosition(m_virtContext, articular_position)) {
650 int err = virtGetErrorCode(m_virtContext);
651 delete [] articular_position;
652 throw(vpException(vpException::fatalError, "Error calling virtSetArticularPosition: error code %d", err));
653 }
654 delete[] articular_position;
655 }
656
657 /*!
658 * Send a command of articular (joint) velocity to the virtuose.
659 * This function works only in COMMAND_TYPE_ARTICULAR mode, to be set with
660 * setCommandType().
661 *
662 * \param articularVelocity : Six dimension joint velocity vector.
663 */
setArticularVelocity(const vpColVector & articularVelocity)664 void vpVirtuose::setArticularVelocity(const vpColVector &articularVelocity)
665 {
666 init();
667
668 if (articularVelocity.size() != m_njoints) {
669 throw(vpException(vpException::dimensionError,
670 "Cannot send an articular velocity command (dim %d) to "
671 "the haptic device that is not %d-dimension",
672 m_njoints, articularVelocity.size()));
673 }
674
675 float *articular_velocity = new float [m_njoints];
676 for (unsigned int i = 0; i < m_njoints; i++)
677 articular_velocity[i] = (float)articularVelocity[i];
678
679 if (virtSetArticularSpeed(m_virtContext, articular_velocity)) {
680 int err = virtGetErrorCode(m_virtContext);
681 delete [] articular_velocity;
682 throw(vpException(vpException::fatalError, "Error calling virtSetArticularVelocity: error code %d", err));
683 }
684 delete[] articular_velocity;
685 }
686
687 /*!
688 * Move the base frame with respect to the observation reference frame.
689 * It can be called at any time.
690 * \param position : Position of the base frame.
691 *
692 * \sa getBaseFrame(), setObservationFrame()
693 */
setBaseFrame(const vpPoseVector & position)694 void vpVirtuose::setBaseFrame(const vpPoseVector &position)
695 {
696 init();
697
698 float position_[7];
699 vpTranslationVector translation;
700 vpQuaternionVector quaternion;
701
702 position.extract(translation);
703 position.extract(quaternion);
704
705 for (int i = 0; i < 3; i++)
706 position_[i] = (float)translation[i];
707 for (int i = 0; i < 4; i++)
708 position_[3 + i] = (float)quaternion[i];
709
710 if (virtSetBaseFrame(m_virtContext, position_)) {
711 int err = virtGetErrorCode(m_virtContext);
712 throw(vpException(vpException::fatalError, "Error calling virtSetBaseFrame: error code %d", err));
713 }
714 }
715
716 /*!
717 * Set the command type.
718 * \param type : Possible values:
719 * - COMMAND_TYPE_NONE : No possible movement.
720 * - COMMAND_TYPE_IMPEDANCE : Force/position control.
721 * - COMMAND_TYPE_VIRTMECH : Position/force control with virtual mechanism.
722 * - COMMAND_TYPE_ARTICULAR : Joint control.
723 * - COMMAND_TYPE_ARTICULAR_IMPEDANCE : Force/Position control in the joint
724 * space.
725 */
setCommandType(const VirtCommandType & type)726 void vpVirtuose::setCommandType(const VirtCommandType &type)
727 {
728 init();
729
730 if (m_typeCommand != type) {
731 m_typeCommand = type;
732
733 if (virtSetCommandType(m_virtContext, m_typeCommand)) {
734 int err = virtGetErrorCode(m_virtContext);
735 throw(vpException(vpException::fatalError, "Error calling virtSetCommandType: error code %d", err));
736 }
737 }
738 }
739
740 /*!
741 * Set the force to be applied by the Virtuose.
742 * setForce() only works in COMMAND_TYPE_IMPEDANCE mode, to be set with
743 * setCommandType(). \param force : Force vector that represents a dynamic
744 * tensor with 6 components.
745 */
setForce(const vpColVector & force)746 void vpVirtuose::setForce(const vpColVector &force)
747 {
748 init();
749
750 if (force.size() != 6) {
751 throw(vpException(vpException::dimensionError,
752 "Cannot apply a force feedback (dim %d) to the haptic "
753 "device that is not 6-dimension",
754 force.size()));
755 }
756
757 float virtforce[6];
758 for (unsigned int i = 0; i < 6; i++)
759 virtforce[i] = (float)force[i];
760
761 if (virtSetForce(m_virtContext, virtforce)) {
762 int err = virtGetErrorCode(m_virtContext);
763 throw(vpException(vpException::fatalError, "Error calling virtSetForce: error code %d", err));
764 }
765 }
766
767 /*!
768 * Set the force scale factor.
769 * \param forceFactor : Force scale factor applied to the force torque tensor
770 * set by setForce().
771 */
setForceFactor(const float & forceFactor)772 void vpVirtuose::setForceFactor(const float &forceFactor)
773 {
774 init();
775
776 if (virtSetForceFactor(m_virtContext, forceFactor)) {
777 int err = virtGetErrorCode(m_virtContext);
778 throw(vpException(vpException::fatalError, "Error calling virtSetForceFactor: error code %d", err));
779 }
780 }
781
782 /*!
783 * Set indexing (offset) mode.
784 * \param type : Possible choices are:
785 * - INDEXING_ALL : authorize indexing on all movements.
786 * - INDEXING_TRANS : authorize indexing on translation, i.e., the orientation
787 * of the object is always identical to the orientation of the device
788 * end-effector.
789 * - INDEXING_NONE : forbids indexing on all movements.
790 * - The following values are also implemented:
791 * INDEXING_ALL_FORCE_FEEDBACK_INHIBITION,
792 * INDEXING_TRANS_FORCE_FEEDBACK_INHIBITION. These values correspond to the
793 * same modes listed before, but the force feedback is inhibited during
794 * indexing.
795 */
setIndexingMode(const VirtIndexingType & type)796 void vpVirtuose::setIndexingMode(const VirtIndexingType &type)
797 {
798 init();
799
800 if (m_indexType != type) {
801 m_indexType = type;
802
803 if (virtSetIndexingMode(m_virtContext, m_indexType)) {
804 int err = virtGetErrorCode(m_virtContext);
805 throw(vpException(vpException::fatalError, "Error calling setIndexingMode: error code %d", err));
806 }
807 }
808 }
809
810 /*!
811 * Move the observation frame with respect to the environment reference frame.
812 * It can be called at any time.
813 * \param position : Position of the observation frame.
814 *
815 * \sa getObservationFrame(), setBaseFrame()
816 */
setObservationFrame(const vpPoseVector & position)817 void vpVirtuose::setObservationFrame(const vpPoseVector &position)
818 {
819 init();
820
821 float position_[7];
822 vpTranslationVector translation;
823 vpQuaternionVector quaternion;
824
825 position.extract(translation);
826 position.extract(quaternion);
827
828 for (int i = 0; i < 3; i++)
829 position_[i] = (float)translation[i];
830 for (int i = 0; i < 4; i++)
831 position_[3 + i] = (float)quaternion[i];
832
833 if (virtSetObservationFrame(m_virtContext, position_)) {
834 int err = virtGetErrorCode(m_virtContext);
835 throw(vpException(vpException::fatalError, "Error calling virtSetObservationFrame: error code %d", err));
836 }
837 }
838
839 /*!
840 * Register the periodic function.
841 * setPeriodicFunction() defines a callback function to be called at a fixed
842 period of time, as timing for the simulation.
843 * The callback function is synchronized with the Virtuose controller
844 (messages arrive at very constant time intervals from it)
845 * and generates hardware interrupts to be taken into account by the operating
846 system.
847 * In practice, this function is much more efficient for timing the simulation
848 than common software timers.
849 * This function is started using startPeriodicFunction() and stopped using
850 stopPeriodicFunction().
851 * \param CallBackVirt : Callback function.
852 *
853 * Example of the use of the periodic function:
854 \code
855 #include <visp3/robot/vpVirtuose.h>
856
857 void CallBackVirtuose(VirtContext VC, void* ptr)
858 {
859 (void) VC;
860 vpVirtuose* p_virtuose=(vpVirtuose*)ptr;
861 vpPoseVector position = p_virtuose->getPosition();
862 return;
863 }
864
865 int main()
866 {
867 vpVirtuose virtuose;
868 float period = 0.001;
869 virtuose.setTimeStep(period);
870 virtuose.setPeriodicFunction(CallBackVirtuose, period, virtuose);
871 virtuose.startPeriodicFunction();
872 virtuose.stopPeriodicFunction();
873 }
874 \endcode
875
876 \sa startPeriodicFunction(), stopPeriodicFunction()
877 */
setPeriodicFunction(VirtPeriodicFunction CallBackVirt)878 void vpVirtuose::setPeriodicFunction(VirtPeriodicFunction CallBackVirt)
879 {
880 init();
881
882 if (virtSetPeriodicFunction(m_virtContext, CallBackVirt, &m_period, this)) {
883 int err = virtGetErrorCode(m_virtContext);
884 throw(vpException(vpException::fatalError, "Error calling virtSetPeriodicFunction: error code %d", err));
885 }
886 }
887
888 /*!
889 * Modify the current value of the control position and send it to the
890 * Virtuose. \param position : Position of the end-effector (or the attached
891 * object, if any).
892 */
setPosition(vpPoseVector & position)893 void vpVirtuose::setPosition(vpPoseVector &position)
894 {
895 init();
896
897 float position_[7];
898 vpTranslationVector translation;
899 vpQuaternionVector quaternion;
900
901 position.extract(translation);
902 position.extract(quaternion);
903
904 for (int i = 0; i < 3; i++)
905 position_[i] = (float)translation[i];
906 for (int i = 0; i < 4; i++)
907 position_[3 + i] = (float)quaternion[i];
908
909 if (virtSetPosition(m_virtContext, position_)) {
910 int err = virtGetErrorCode(m_virtContext);
911 throw(vpException(vpException::fatalError, "Error calling virtSetPosition: error code %d", err));
912 }
913 }
914
915 /*!
916 * Turn the motor power OFF.
917 */
setPowerOff()918 void vpVirtuose::setPowerOff()
919 {
920 init();
921
922 if (virtSetPowerOn(m_virtContext, 0)) {
923 int err = virtGetErrorCode(m_virtContext);
924 throw(vpException(vpException::fatalError, "Error calling virtSetPowerOff: error code %d", err));
925 }
926 }
927
928 /*!
929 * Turn the motor power ON.
930 */
setPowerOn()931 void vpVirtuose::setPowerOn()
932 {
933 init();
934
935 if (virtSetPowerOn(m_virtContext, 1)) {
936 int err = virtGetErrorCode(m_virtContext);
937 throw(vpException(vpException::fatalError, "Error calling virtSetPowerOn: error code %d", err));
938 }
939 }
940
941 /*!
942 * Set saturation values of the force feedback
943 * \param forceLimit : Value expressed in N.
944 * \param torqueLimit : Value expressed in Nm.
945 */
setSaturation(const float & forceLimit,const float & torqueLimit)946 void vpVirtuose::setSaturation(const float &forceLimit, const float &torqueLimit)
947 {
948 init();
949
950 if (virtSaturateTorque(m_virtContext, forceLimit, torqueLimit)) {
951 int err = virtGetErrorCode(m_virtContext);
952 throw(vpException(vpException::fatalError, "Error calling virtSaturateTorque: error code %d", err));
953 }
954 }
955
956 /*!
957 * Set the the simulation time step.
958 * The function must be called before the selection of the type of control
959 * mode. \param timeStep : Simulation time step (seconds).
960 */
setTimeStep(const float & timeStep)961 void vpVirtuose::setTimeStep(const float &timeStep)
962 {
963 init();
964
965 if (m_period != timeStep) {
966 m_period = timeStep;
967
968 if (virtSetTimeStep(m_virtContext, m_period)) {
969 int err = virtGetErrorCode(m_virtContext);
970 throw(vpException(vpException::fatalError, "Error calling virtSetTimeStep: error code %d", err));
971 }
972 }
973 }
974
975 /*!
976 * Modify the current value of the control velocity and send it to the
977 * Virtuose. \param velocity : Velocity twist vector, where translations
978 * velocities are expressed in m/s and rotation velocities in rad/s.
979 */
setVelocity(vpColVector & velocity)980 void vpVirtuose::setVelocity(vpColVector &velocity)
981 {
982 init();
983
984 if (velocity.size() != 6) {
985 throw(vpException(vpException::dimensionError, "Cannot set a velocity vector (dim %d) that is not 6-dimension",
986 velocity.size()));
987 }
988
989 float speed[6];
990 for (unsigned int i = 0; i < 6; i++)
991 speed[i] = (float)velocity[i];
992
993 if (virtSetSpeed(m_virtContext, speed)) {
994 int err = virtGetErrorCode(m_virtContext);
995 throw(vpException(vpException::fatalError, "Error calling virtSetSpeed: error code %d", err));
996 }
997 }
998
999 /*!
1000 * Set the speed factor.
1001 * \param velocityFactor : Scale factor applied to the velocities set using
1002 * setVelocity().
1003 */
setVelocityFactor(const float & velocityFactor)1004 void vpVirtuose::setVelocityFactor(const float &velocityFactor)
1005 {
1006 init();
1007
1008 if (virtSetSpeedFactor(m_virtContext, velocityFactor)) {
1009 int err = virtGetErrorCode(m_virtContext);
1010 throw(vpException(vpException::fatalError, "Error calling setVelocityFactor: error code %d", err));
1011 }
1012 }
1013
1014 /*!
1015 * Start the callback function set with setPeriodicFunction().
1016 *
1017 * \sa stopPeriodicFunction(), setPeriodicFunction()
1018 */
startPeriodicFunction()1019 void vpVirtuose::startPeriodicFunction()
1020 {
1021 init();
1022
1023 if (virtStartLoop(m_virtContext)) {
1024 int err = virtGetErrorCode(m_virtContext);
1025 throw(vpException(vpException::fatalError, "Error calling startLoop: error code %d", err));
1026 } else
1027 std::cout << "Haptic loop open." << std::endl;
1028 }
1029
1030 /*!
1031 * Stop the callback function set with setPeriodicFunction().
1032 *
1033 * \sa startPeriodicFunction(), setPeriodicFunction()
1034 */
stopPeriodicFunction()1035 void vpVirtuose::stopPeriodicFunction()
1036 {
1037 init();
1038
1039 if (virtStopLoop(m_virtContext)) {
1040 int err = virtGetErrorCode(m_virtContext);
1041 throw(vpException(vpException::fatalError, "Error calling stopLoop: error code %d", err));
1042 } else
1043 std::cout << "Haptic loop closed." << std::endl;
1044 }
1045
1046 #else
1047 // Work around to avoid warning
dummy_vpVirtuose()1048 void dummy_vpVirtuose(){};
1049 #endif
1050