File: testVirtuoseHapticBox.cpp

package info (click to toggle)
visp 3.7.0-7
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 166,380 kB
  • sloc: cpp: 392,705; ansic: 224,448; xml: 23,444; python: 13,701; java: 4,792; sh: 206; objc: 145; makefile: 118
file content (308 lines) | stat: -rw-r--r-- 9,308 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
 * ViSP, open source Visual Servoing Platform software.
 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
 *
 * This software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * See the file LICENSE.txt at the root directory of this source
 * distribution for additional information about the GNU GPL.
 *
 * For using ViSP with software that can not be combined with the GNU
 * GPL, please contact Inria about acquiring a ViSP Professional
 * Edition License.
 *
 * See https://visp.inria.fr for more information.
 *
 * This software was developed at:
 * Inria Rennes - Bretagne Atlantique
 * Campus Universitaire de Beaulieu
 * 35042 Rennes Cedex
 * France
 *
 * If you have questions regarding the use of this file, please contact
 * Inria at visp@inria.fr
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description:
 * Test for Virtuose SDK wrapper.
 */

/*!
  \example testVirtuoseHapticBox.cpp

  Test Haption Virtuose SDK wrapper to constrain movements inside a cube of
  pre-determined side. Hard springs are applied to rotations (only
  translations are allowed).
*/

#include <visp3/core/vpTime.h>
#include <visp3/robot/vpVirtuose.h>

#if defined(VISP_HAVE_VIRTUOSE)
#ifdef ENABLE_VISP_NAMESPACE
using namespace VISP_NAMESPACE_NAME;
#endif

void CallBackVirtuose(VirtContext VC, void *ptr)
{
  (void)VC;

  static bool firstIteration = true;
  static vpPoseVector localPosition0;

  vpPoseVector localPosition;
  vpColVector forceFeedback(6, 0);
  vpColVector finalForce(6, 0);
  vpColVector forceEe(6, 0);
  int force_limit = 15;
  int force_increase_rate = 500;
  float cube_size = 0.05f;

  // Virtual spring to let the user know where the initial position is
  // Estimated Virtuose handle mass = 0.1;
  // Estimated Virtuose handle length = 0.23;
  // In the ee frame: Virtuose Handle as a cylinder for the inertia
  // Estimated Inertia1 = m*l*l/12
  // Estimated Inertia2 = m*l*l/2 (rotation w.r.t. e-e z axis)
  double virtualStiffnessAng = 20;
  double virtualDamperAng = 0.182;   // greater than sqrt 4*Inertia1*virtualStiffnessAng
  double virtualDamperAng2 = 0.0456; // greater than sqrt 4*Inertia2*virtualStiffnessAng

  vpColVector xd(3, 0);
  vpColVector yd(3, 0);
  vpColVector zd(3, 0);
  vpColVector xee(3, 0);
  vpColVector zee(3, 0);
  vpColVector xeed(3, 0);
  vpColVector zeed(3, 0);
  vpColVector zYZ(3, 0);
  vpColVector zXZ(3, 0);
  vpColVector xXY(3, 0);
  vpTranslationVector tee;
  vpColVector omegad(3, 0);
  vpRotationMatrix Qd;
  vpRotationMatrix Qee;
  vpPoseVector pee;
  vpColVector vee(6, 0);
  vpColVector veed(6, 0);

  double alpha;

  vpColVector torque1(3, 0);
  vpColVector torque2(3, 0);
  vpColVector torque3(3, 0);

  vpVirtuose *p_virtuose = (vpVirtuose *)ptr;
  localPosition = p_virtuose->getPhysicalPosition();

  if (firstIteration) {
    localPosition0 = localPosition;
    firstIteration = false;
  }

  //  Position and velocity in of the ee expressed in the base frame
  pee = localPosition;
  vee = p_virtuose->getPhysicalVelocity();
  // Z axis = [pee_x pee_y 0]
  zd[0] = pee[0];
  zd[1] = pee[1];
  zd.normalize();
  // X axis = [0 0 1]
  xd[2] = 1;
  // Y axis from cross product
  yd = zd.skew(zd) * xd;

  // Current orientation of the ee frame
  pee.extract(Qee);
  pee.extract(tee);
  // X and Z axis of the ee frame expressed in the base frame
  xee = Qee.getCol(0);
  zee = Qee.getCol(2);

  // Rotation matrix from Desired Frame to Base Frame
  Qd[0][0] = xd[0];
  Qd[1][0] = xd[1];
  Qd[2][0] = xd[2];
  Qd[0][1] = yd[0];
  Qd[1][1] = yd[1];
  Qd[2][1] = yd[2];
  Qd[0][2] = zd[0];
  Qd[1][2] = zd[1];
  Qd[2][2] = zd[2];

  // X and Z axis of the ee frame expressed in the desired frame
  xeed = Qd.inverse() * xee;
  zeed = Qd.inverse() * zee;

  vpHomogeneousMatrix dMb(tee, Qd);
  // Velocity twist matrix for expressing velocities in the desired frame
  vpVelocityTwistMatrix dVMb(dMb.inverse());
  // Force twist matrix for expressing forces in the base frame
  vpForceTwistMatrix dFMb(dMb);

  veed = dVMb * vee;

  // Angular velocity in the desired frame
  omegad[0] = veed[3];
  omegad[1] = veed[4];
  omegad[2] = veed[5];

  // Projection of Z axis of the ee frame onto plane YZ (expressed in the
  // desired frame)
  zYZ[1] = zeed[1];
  zYZ[2] = zeed[2];

  // Projection of Z axis of the ee frame onto plane XZ (expressed in the
  // desired frame)
  zXZ[0] = zeed[0];
  zXZ[2] = zeed[2];

  // Hard spring to keep Z axis of the ee frame in the horizontal plane
  // Spring applied to the angle between the Z axis of the ee frame and its
  // projection in the YZ (horizontal) plane
  vpColVector rotzYZ(3, 0);
  rotzYZ = zeed.skew(zeed) * zYZ.normalize();
  vpColVector forceStiff1 = virtualStiffnessAng * rotzYZ;
  vpColVector forceDamp1 = virtualDamperAng * (omegad * rotzYZ.normalize()) * rotzYZ.normalize();

  for (unsigned int i = 0; i < 3; i++)
    torque1[i] = forceStiff1[i] - forceDamp1[i];

  // Hard spring to keep Z axis of the ee frame pointing at the origin
  // Spring applied to the angle between the Z axis of the ee frame and its
  // projection in the XZ (vertical) plane
  vpColVector rotzXZ(3, 0);
  rotzXZ = zeed.skew(zeed) * zXZ.normalize();
  vpColVector forceStiff2 = virtualStiffnessAng * rotzXZ;
  vpColVector forceDamp2 = virtualDamperAng * (omegad * rotzXZ.normalize()) * rotzXZ.normalize();

  for (unsigned int i = 0; i < 3; i++)
    torque2[i] = forceStiff2[i] - forceDamp2[i];

  // Hard spring for rotation around z axis of the ee
  xXY[0] = xeed[0];
  xXY[1] = xeed[1];
  vpColVector xdd(3, 0);
  xdd[0] = 1;
  vpColVector zdd(3, 0);
  zdd[2] = 1;
  vpColVector rotxXY(3, 0);
  rotxXY = xdd.skew(xdd) * xXY.normalize();
  alpha = asin(rotxXY[2]);

  vpColVector forceStiff3 = virtualStiffnessAng * alpha * zdd;
  vpColVector forceDamp3 = virtualDamperAng2 * (omegad * zdd) * zdd;
  for (unsigned int i = 0; i < 3; i++)
    torque3[i] = forceStiff3[i] - forceDamp3[i];

  for (unsigned int j = 0; j < 3; j++)
    forceEe[j + 3] = torque1[j] + torque2[j] + torque3[j];

  forceEe = dFMb * forceEe;

  // ---------------
  //  Haptic Box
  // ---------------
  vpColVector p_min(3, 0), p_max(3, 0);
  for (unsigned int i = 0; i < 3; i++) {
    p_min[i] = localPosition0[i] - cube_size / 2;
    p_max[i] = localPosition0[i] + cube_size / 2;
  }

  for (int i = 0; i < 3; i++) {
    if ((p_min[i] >= localPosition[i])) {
      forceFeedback[i] = (p_min[i] - localPosition[i]) * force_increase_rate;
      if (forceFeedback[i] >= force_limit)
        forceFeedback[i] = force_limit;
    }
    else if ((p_max[i] <= localPosition[i])) {
      forceFeedback[i] = (p_max[i] - localPosition[i]) * force_increase_rate;
      if (forceFeedback[i] <= -force_limit)
        forceFeedback[i] = -force_limit;
    }
    else
      forceFeedback[i] = 0;
  }

  for (unsigned int j = 0; j < 6; j++)
    finalForce[j] = forceFeedback[j] + forceEe[j];

  // Set force feedback
  p_virtuose->setForce(finalForce);

  return;
}

int main(int argc, char **argv)
{
  std::string opt_ip = "localhost";
  int opt_port = 5000;
  for (int i = 1; i < argc; i++) {
    if (std::string(argv[i]) == "--ip" && i + 1 < argc) {
      opt_ip = std::string(argv[++i]);
    }
    else if (std::string(argv[i]) == "--port" && i + 1 < argc) {
      opt_port = std::atoi(argv[++i]);
    }
    else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
      std::cout << "\nUsage: " << argv[0]
        << " [--ip <localhost>] [--port <port>]"
        " [--help] [-h]\n"
        << std::endl
        << "Description: " << std::endl
        << " --ip <localhost>" << std::endl
        << "\tHost IP address. Default value: \"localhost\"." << std::endl
        << std::endl
        << " --port <port>" << std::endl
        << "\tCommunication port. Default value: 5000." << std::endl
        << "\tSuggested values: " << std::endl
        << "\t- 5000 to communicate with the Virtuose." << std::endl
        << "\t- 53210 to communicate with the Virtuose equipped with the Glove." << std::endl
        << std::endl;
      return EXIT_SUCCESS;
    }
  }

  try {
    vpVirtuose virtuose;
    std::cout << "Try to connect to " << opt_ip << " port " << opt_port << std::endl;
    virtuose.setIpAddressAndPort(opt_ip, opt_port);
    virtuose.setVerbose(true);
    virtuose.setPowerOn();
    virtuose.setPeriodicFunction(CallBackVirtuose);
    virtuose.startPeriodicFunction();

    int counter = 0;
    bool swtch = true;

    while (swtch) {
      if (counter >= 10) {
        virtuose.stopPeriodicFunction();
        virtuose.setPowerOff();
        swtch = false;
      }
      counter++;
      vpTime::sleepMs(1000);
    }
    std::cout << "The end" << std::endl;
  }
  catch (const vpException &e) {
    std::cout << "Catch an exception: " << e.getStringMessage() << std::endl;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

#else
int main()
{
  std::cout << "You should install pthread and/or Virtuose API to use this "
    "binary..."
    << std::endl;
  return EXIT_SUCCESS;
}
#endif