Visual Servoing Platform  version 3.6.1 under development (2024-12-17)
testVirtuoseHapticBox.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  * Test for Virtuose SDK wrapper.
32  */
33 
42 #include <visp3/core/vpTime.h>
43 #include <visp3/robot/vpVirtuose.h>
44 
45 #if defined(VISP_HAVE_VIRTUOSE)
46 #ifdef ENABLE_VISP_NAMESPACE
47 using namespace VISP_NAMESPACE_NAME;
48 #endif
49 
50 void CallBackVirtuose(VirtContext VC, void *ptr)
51 {
52  (void)VC;
53 
54  static bool firstIteration = true;
55  static vpPoseVector localPosition0;
56 
57  vpPoseVector localPosition;
58  vpColVector forceFeedback(6, 0);
59  vpColVector finalForce(6, 0);
60  vpColVector forceEe(6, 0);
61  int force_limit = 15;
62  int force_increase_rate = 500;
63  float cube_size = 0.05f;
64 
65  // Virtual spring to let the user know where the initial position is
66  // Estimated Virtuose handle mass = 0.1;
67  // Estimated Virtuose handle length = 0.23;
68  // In the ee frame: Virtuose Handle as a cylinder for the inertia
69  // Estimated Inertia1 = m*l*l/12
70  // Estimated Inertia2 = m*l*l/2 (rotation w.r.t. e-e z axis)
71  double virtualStiffnessAng = 20;
72  double virtualDamperAng = 0.182; // greater than sqrt 4*Inertia1*virtualStiffnessAng
73  double virtualDamperAng2 = 0.0456; // greater than sqrt 4*Inertia2*virtualStiffnessAng
74 
75  vpColVector xd(3, 0);
76  vpColVector yd(3, 0);
77  vpColVector zd(3, 0);
78  vpColVector xee(3, 0);
79  vpColVector zee(3, 0);
80  vpColVector xeed(3, 0);
81  vpColVector zeed(3, 0);
82  vpColVector zYZ(3, 0);
83  vpColVector zXZ(3, 0);
84  vpColVector xXY(3, 0);
86  vpColVector omegad(3, 0);
88  vpRotationMatrix Qee;
89  vpPoseVector pee;
90  vpColVector vee(6, 0);
91  vpColVector veed(6, 0);
92 
93  double alpha;
94 
95  vpColVector torque1(3, 0);
96  vpColVector torque2(3, 0);
97  vpColVector torque3(3, 0);
98 
99  vpVirtuose *p_virtuose = (vpVirtuose *)ptr;
100  localPosition = p_virtuose->getPhysicalPosition();
101 
102  if (firstIteration) {
103  localPosition0 = localPosition;
104  firstIteration = false;
105  }
106 
107  // Position and velocity in of the ee expressed in the base frame
108  pee = localPosition;
109  vee = p_virtuose->getPhysicalVelocity();
110  // Z axis = [pee_x pee_y 0]
111  zd[0] = pee[0];
112  zd[1] = pee[1];
113  zd.normalize();
114  // X axis = [0 0 1]
115  xd[2] = 1;
116  // Y axis from cross product
117  yd = zd.skew(zd) * xd;
118 
119  // Current orientation of the ee frame
120  pee.extract(Qee);
121  pee.extract(tee);
122  // X and Z axis of the ee frame expressed in the base frame
123  xee = Qee.getCol(0);
124  zee = Qee.getCol(2);
125 
126  // Rotation matrix from Desired Frame to Base Frame
127  Qd[0][0] = xd[0];
128  Qd[1][0] = xd[1];
129  Qd[2][0] = xd[2];
130  Qd[0][1] = yd[0];
131  Qd[1][1] = yd[1];
132  Qd[2][1] = yd[2];
133  Qd[0][2] = zd[0];
134  Qd[1][2] = zd[1];
135  Qd[2][2] = zd[2];
136 
137  // X and Z axis of the ee frame expressed in the desired frame
138  xeed = Qd.inverse() * xee;
139  zeed = Qd.inverse() * zee;
140 
141  vpHomogeneousMatrix dMb(tee, Qd);
142  // Velocity twist matrix for expressing velocities in the desired frame
143  vpVelocityTwistMatrix dVMb(dMb.inverse());
144  // Force twist matrix for expressing forces in the base frame
145  vpForceTwistMatrix dFMb(dMb);
146 
147  veed = dVMb * vee;
148 
149  // Angular velocity in the desired frame
150  omegad[0] = veed[3];
151  omegad[1] = veed[4];
152  omegad[2] = veed[5];
153 
154  // Projection of Z axis of the ee frame onto plane YZ (expressed in the
155  // desired frame)
156  zYZ[1] = zeed[1];
157  zYZ[2] = zeed[2];
158 
159  // Projection of Z axis of the ee frame onto plane XZ (expressed in the
160  // desired frame)
161  zXZ[0] = zeed[0];
162  zXZ[2] = zeed[2];
163 
164  // Hard spring to keep Z axis of the ee frame in the horizontal plane
165  // Spring applied to the angle between the Z axis of the ee frame and its
166  // projection in the YZ (horizontal) plane
167  vpColVector rotzYZ(3, 0);
168  rotzYZ = zeed.skew(zeed) * zYZ.normalize();
169  vpColVector forceStiff1 = virtualStiffnessAng * rotzYZ;
170  vpColVector forceDamp1 = virtualDamperAng * (omegad * rotzYZ.normalize()) * rotzYZ.normalize();
171 
172  for (unsigned int i = 0; i < 3; i++)
173  torque1[i] = forceStiff1[i] - forceDamp1[i];
174 
175  // Hard spring to keep Z axis of the ee frame pointing at the origin
176  // Spring applied to the angle between the Z axis of the ee frame and its
177  // projection in the XZ (vertical) plane
178  vpColVector rotzXZ(3, 0);
179  rotzXZ = zeed.skew(zeed) * zXZ.normalize();
180  vpColVector forceStiff2 = virtualStiffnessAng * rotzXZ;
181  vpColVector forceDamp2 = virtualDamperAng * (omegad * rotzXZ.normalize()) * rotzXZ.normalize();
182 
183  for (unsigned int i = 0; i < 3; i++)
184  torque2[i] = forceStiff2[i] - forceDamp2[i];
185 
186  // Hard spring for rotation around z axis of the ee
187  xXY[0] = xeed[0];
188  xXY[1] = xeed[1];
189  vpColVector xdd(3, 0);
190  xdd[0] = 1;
191  vpColVector zdd(3, 0);
192  zdd[2] = 1;
193  vpColVector rotxXY(3, 0);
194  rotxXY = xdd.skew(xdd) * xXY.normalize();
195  alpha = asin(rotxXY[2]);
196 
197  vpColVector forceStiff3 = virtualStiffnessAng * alpha * zdd;
198  vpColVector forceDamp3 = virtualDamperAng2 * (omegad * zdd) * zdd;
199  for (unsigned int i = 0; i < 3; i++)
200  torque3[i] = forceStiff3[i] - forceDamp3[i];
201 
202  for (unsigned int j = 0; j < 3; j++)
203  forceEe[j + 3] = torque1[j] + torque2[j] + torque3[j];
204 
205  forceEe = dFMb * forceEe;
206 
207  // ---------------
208  // Haptic Box
209  // ---------------
210  vpColVector p_min(3, 0), p_max(3, 0);
211  for (unsigned int i = 0; i < 3; i++) {
212  p_min[i] = localPosition0[i] - cube_size / 2;
213  p_max[i] = localPosition0[i] + cube_size / 2;
214  }
215 
216  for (int i = 0; i < 3; i++) {
217  if ((p_min[i] >= localPosition[i])) {
218  forceFeedback[i] = (p_min[i] - localPosition[i]) * force_increase_rate;
219  if (forceFeedback[i] >= force_limit)
220  forceFeedback[i] = force_limit;
221  }
222  else if ((p_max[i] <= localPosition[i])) {
223  forceFeedback[i] = (p_max[i] - localPosition[i]) * force_increase_rate;
224  if (forceFeedback[i] <= -force_limit)
225  forceFeedback[i] = -force_limit;
226  }
227  else
228  forceFeedback[i] = 0;
229  }
230 
231  for (unsigned int j = 0; j < 6; j++)
232  finalForce[j] = forceFeedback[j] + forceEe[j];
233 
234  // Set force feedback
235  p_virtuose->setForce(finalForce);
236 
237  return;
238 }
239 
240 int main(int argc, char **argv)
241 {
242  std::string opt_ip = "localhost";
243  int opt_port = 5000;
244  for (int i = 0; i < argc; i++) {
245  if (std::string(argv[i]) == "--ip")
246  opt_ip = std::string(argv[i + 1]);
247  else if (std::string(argv[i]) == "--port")
248  opt_port = std::atoi(argv[i + 1]);
249  else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
250  std::cout << "\nUsage: " << argv[0]
251  << " [--ip <localhost>] [--port <port>]"
252  " [--help] [-h]\n"
253  << std::endl
254  << "Description: " << std::endl
255  << " --ip <localhost>" << std::endl
256  << "\tHost IP address. Default value: \"localhost\"." << std::endl
257  << std::endl
258  << " --port <port>" << std::endl
259  << "\tCommunication port. Default value: 5000." << std::endl
260  << "\tSuggested values: " << std::endl
261  << "\t- 5000 to communicate with the Virtuose." << std::endl
262  << "\t- 53210 to communicate with the Virtuose equipped with the Glove." << std::endl
263  << std::endl;
264  return EXIT_SUCCESS;
265  }
266  }
267 
268  try {
269  vpVirtuose virtuose;
270  std::cout << "Try to connect to " << opt_ip << " port " << opt_port << std::endl;
271  virtuose.setIpAddressAndPort(opt_ip, opt_port);
272  virtuose.setVerbose(true);
273  virtuose.setPowerOn();
274  virtuose.setPeriodicFunction(CallBackVirtuose);
275  virtuose.startPeriodicFunction();
276 
277  int counter = 0;
278  bool swtch = true;
279 
280  while (swtch) {
281  if (counter >= 10) {
282  virtuose.stopPeriodicFunction();
283  virtuose.setPowerOff();
284  swtch = false;
285  }
286  counter++;
287  vpTime::sleepMs(1000);
288  }
289  std::cout << "The end" << std::endl;
290  }
291  catch (const vpException &e) {
292  std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
293  return EXIT_FAILURE;
294  }
295  return EXIT_SUCCESS;
296 }
297 
298 #else
299 int main()
300 {
301  std::cout << "You should install pthread and/or Virtuose API to use this "
302  "binary..."
303  << std::endl;
304  return EXIT_SUCCESS;
305 }
306 #endif
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
vpColVector & normalize()
error that can be emitted by ViSP classes.
Definition: vpException.h:60
const std::string & getStringMessage() const
Definition: vpException.cpp:67
Implementation of an homogeneous matrix and operations on such kind of matrices.
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:203
void extract(vpRotationMatrix &R) const
Implementation of a rotation matrix and operations on such kind of matrices.
vpColVector getCol(unsigned int j) const
vpRotationMatrix inverse() const
Class that consider the case of a translation vector.
void setIpAddressAndPort(const std::string &ip, int port)
Definition: vpVirtuose.cpp:81
void setPowerOff()
Definition: vpVirtuose.cpp:925
void setForce(const vpColVector &force)
Definition: vpVirtuose.cpp:749
vpPoseVector getPhysicalPosition() const
Definition: vpVirtuose.cpp:418
void setPeriodicFunction(VirtPeriodicFunction CallBackVirt)
Definition: vpVirtuose.cpp:885
void stopPeriodicFunction()
void setPowerOn()
Definition: vpVirtuose.cpp:938
void setVerbose(bool mode)
Definition: vpVirtuose.h:196
void startPeriodicFunction()
vpColVector getPhysicalVelocity() const
Definition: vpVirtuose.cpp:452
VISP_EXPORT void sleepMs(double t)