PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusOpenHapticsDevice.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Author: Sam Horvath, Kitware, Inc.
4 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
5 See License.txt for details.
6 =========================================================Plus=header=end*/
7 
8 
9 // Local includes
10 #include "PlusConfigure.h"
11 #include "vtkPlusDataSource.h"
13 
14 //HD includes
15 #include <HDU/hduVector.h>
16 #include <HDU/hduError.h>
17 #include <HD/hd.h>
18 
19 // VTK includes
20 #include <vtkMatrix4x4.h>
21 #include <vtkTransform.h>
22 
23 // STL includes
24 #include <fstream>
25 #include <iostream>
26 #include <sstream>
27 
29 
30 //----------------------------------------------------------------------------
32  : FrameNumber(-1)
33  , DeviceHandle(-1)
34  , DeviceName("Default Device")
35  , toolTransform(vtkSmartPointer<vtkTransform>::New())
36  , rotation(vtkSmartPointer<vtkTransform>::New())
37  , velMatrix(vtkSmartPointer<vtkMatrix4x4>::New())
38  , buttonMatrix(vtkSmartPointer<vtkMatrix4x4>::New())
39  , toolMatrix(vtkSmartPointer<vtkMatrix4x4>::New())
40 {
42  this->StartThreadForInternalUpdates = true;
43  this->AcquisitionRate = 20;
44 }
45 
46 //----------------------------------------------------------------------------
48 
49 //----------------------------------------------------------------------------
51 {
52  std::stringstream ss;
53  ss << HD_VERSION_MAJOR_NUMBER << "." << HD_VERSION_MINOR_NUMBER << "." << HD_VERSION_BUILD_NUMBER;
54  return ss.str();
55 }
56 
57 //----------------------------------------------------------------------------
59 {
60  if(this->Connected)
61  {
62  LOG_ERROR("vtkPlusOpenHapticsDevice::Probe should not be called while the device is already initialized");
63  return PLUS_FAIL;
64  }
65  if(this->InternalConnect())
66  {
67  this->InternalDisconnect();
68  LOG_INFO("vtkPlusOpenHapticsDevice::Probe found OpenHaptics Device");
69  return PLUS_SUCCESS;
70  }
71  else
72  {
73  LOG_ERROR("vtkPlusOpenHapticsDevice::Probe failed to connect to device");
74  return PLUS_FAIL;
75  }
76 
77 }
78 
79 //----------------------------------------------------------------------------
81 {
82  //schedule the internal callback - must be done each time device is polled
83  //the scheduler is intended to manage multiple clients requesting data from the same device
84  hdScheduleSynchronous(positionCallback, this, HD_MAX_SCHEDULER_PRIORITY);
85 
86  return PLUS_SUCCESS;
87 }
88 
89 //----------------------------------------------------------------------------
91 {
92 
93  HDErrorInfo errorFlush;
94  while(HD_DEVICE_ERROR(errorFlush = hdGetError())) {}
95 
96  this->DeviceHandle = hdInitDevice(this->DeviceName.c_str());
97 
98  HDErrorInfo error;
99  if(HD_DEVICE_ERROR(error = hdGetError()))
100  {
101  LOG_ERROR("Failed to initialize Phantom Omni " << this->DeviceName);
102  this->DeviceHandle = -1;
103  return PLUS_FAIL;
104  }
105 
106  // Enable forces
107  hdEnable(HD_FORCE_OUTPUT);
108  hdEnable(HD_FORCE_RAMPING);
109 
110  LOG_DEBUG("Phantom initialized: " << this->DeviceName)
111 
112  hdStartScheduler();
113 
114  return PLUS_SUCCESS;
115 }
116 
117 //----------------------------------------------------------------------------
119 {
120  hdDisableDevice(DeviceHandle);
121  hdStopScheduler();
122  return PLUS_SUCCESS;
123 }
124 
125 //----------------------------------------------------------------------------
126 PlusStatus vtkPlusOpenHapticsDevice::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
127 {
128  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
129  XML_READ_STRING_ATTRIBUTE_REQUIRED(DeviceName, deviceConfig);
130  return PLUS_SUCCESS;
131 }
132 
133 //----------------------------------------------------------------------------
134 PlusStatus vtkPlusOpenHapticsDevice::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
135 {
136  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(trackerConfig, rootConfigElement);
137  trackerConfig->SetAttribute("DeviceName", this->DeviceName.c_str());
138  return PLUS_SUCCESS;
139 }
140 
141 //----------------------------------------------------------------------------
143 {
144  if(this->InputChannels.empty())
145  {
146  LOG_INFO("No force input has been provided");
147  }
148  else
149  {
150  if(this->InputChannels.size() > 1)
151  {
152  LOG_INFO("Multiple input channels present. Only first channel will be checked for force data");
153  }
154  vtkPlusDataSource* forceInput;
155  if(this->InputChannels[0]->GetToolByPortName(forceInput, "Force") != PLUS_SUCCESS)
156  {
157  LOG_INFO("No Force tool in input channel. Forces will not be available");
158  }
159  }
160  return PLUS_SUCCESS;
161 }
162 
163 //----------------------------------------------------------------------------
164 HDCallbackCode HDCALLBACK
165 vtkPlusOpenHapticsDevice::positionCallback(void* pData)
166 {
167 
168  vtkPlusOpenHapticsDevice* client = reinterpret_cast<vtkPlusOpenHapticsDevice*>(pData);
169  HHD handle = client->DeviceHandle;
170 
171  const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
172  ++client->FrameNumber;
173 
174  HDdouble force[3];
175  force[0] = 0;
176  force[1] = 0;
177  force[2] = 0;
178 
179 
180  //assemble force data
181  vtkPlusDataSource* forceInput;
182  if(!client->InputChannels.empty() && (client->InputChannels[0]->GetToolByPortName(forceInput, "Force") == PLUS_SUCCESS))
183  {
184  StreamBufferItem item;
185  if(forceInput->GetLatestStreamBufferItem(&item) == ITEM_OK)
186  {
187  if(item.GetStatus() == TOOL_OK)
188  {
189  vtkSmartPointer<vtkMatrix4x4> forceMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
190  item.GetMatrix(forceMatrix);
191  force[0] = forceMatrix->GetElement(0, 3);
192  force[1] = forceMatrix->GetElement(1, 3);
193  force[2] = forceMatrix->GetElement(2, 3);
194  }
195  else
196  {
197  LOG_ERROR("OpenHaptics Force data tool is not valid")
198  }
199  }
200  else
201  {
202  LOG_ERROR("OpenHaptics Force data tool info not recevied")
203  }
204  }
205  else
206  {
207  LOG_TRACE("No force data tool has been provided");
208  }
209 
210  //Current position data is pulled here
211  HDdouble tfm[16];
212  HDdouble pos[3];
213  HDdouble vel[3];
214  HDint buttonVals = 0;
215  HDboolean inkwell = 0;
216  hdBeginFrame(handle);
217  hdMakeCurrentDevice(handle);
218  hdGetDoublev(HD_CURRENT_TRANSFORM, tfm);
219  hdGetDoublev(HD_CURRENT_POSITION, pos);
220  hdGetDoublev(HD_CURRENT_VELOCITY, vel);
221  hdSetDoublev(HD_CURRENT_FORCE, force);
222  hdGetIntegerv(HD_CURRENT_BUTTONS, &buttonVals);
223  hdGetBooleanv(HD_CURRENT_INKWELL_SWITCH, &inkwell);
224  vtkPlusDataSource* stylus = NULL;
225  vtkPlusDataSource* velocity = NULL;
226  vtkPlusDataSource* buttons = NULL;
227  hdEndFrame(handle);
228 
229  double orient[3];
230 
231  //Arrange transformations in correct order
232  client->toolTransform->Identity();
233  client->toolTransform->Translate(pos);
234  client->rotation->SetMatrix(tfm);
235  client->rotation->GetOrientation(orient);
236  client->toolTransform->RotateX(-1 * orient[0] + 180);
237  client->toolTransform->RotateY(orient[1]);
238  client->toolTransform->RotateZ(orient[2]);
239  client->velMatrix->SetElement(0, 3, vel[0]);
240  client->velMatrix->SetElement(1, 3, vel[1]);
241  client->velMatrix->SetElement(2, 3, vel[2]);
242 
243  client->toolMatrix = client->toolTransform->GetMatrix();
244 
245 
246  //Setting the button values in the matrix
247  //The four button occupy the 1st column
248  //The inkwell switch is at the top of the second column.
249  client->buttonMatrix->SetElement(0, 0, 0);
250  client->buttonMatrix->SetElement(1, 1, 0);
251  client->buttonMatrix->SetElement(2, 2, 0);
252  client->buttonMatrix->SetElement(0, 0, (bool)(buttonVals & HD_DEVICE_BUTTON_1));
253  client->buttonMatrix->SetElement(1, 0, (bool)(buttonVals & HD_DEVICE_BUTTON_2));
254  client->buttonMatrix->SetElement(2, 0, (bool)(buttonVals & HD_DEVICE_BUTTON_3));
255  client->buttonMatrix->SetElement(3, 0, (bool)(buttonVals & HD_DEVICE_BUTTON_4));
256  client->buttonMatrix->SetElement(0, 1, (int)inkwell);
257 
258  if(client->GetToolByPortName("Stylus", stylus) == PLUS_SUCCESS)
259  {
260  client->ToolTimeStampedUpdate(stylus->GetId(), client->toolMatrix, TOOL_OK, client->FrameNumber, unfilteredTimestamp);
261  }
262 
263  if(client->GetToolByPortName("StylusVelocity", velocity) == PLUS_SUCCESS)
264  {
265  client->ToolTimeStampedUpdate(velocity->GetId(), client->velMatrix, TOOL_OK, client->FrameNumber, unfilteredTimestamp);
266  }
267 
268  if(client->GetToolByPortName("Buttons", buttons) == PLUS_SUCCESS)
269  {
270  client->ToolTimeStampedUpdate(buttons->GetId(), client->buttonMatrix, TOOL_OK, client->FrameNumber, unfilteredTimestamp);
271  }
272 
273  return HD_CALLBACK_DONE;
274 }
275 
ToolStatus GetStatus() const
Device interface for Open Haptics devices.
vtkStandardNewMacro(vtkPlusOpenHapticsDevice)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
double * velocity
Definition: phidget22.h:3326
igsioStatus PlusStatus
Definition: PlusCommon.h:40
ChannelContainer InputChannels
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
bool RequirePortNameInDeviceSetConfiguration
double AcquisitionRate
virtual std::string GetSdkVersion()
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PlusStatus GetToolByPortName(const char *aPortName, vtkPlusDataSource *&aSource)
PlusStatus GetMatrix(vtkMatrix4x4 *outputMatrix)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual ItemStatus GetLatestStreamBufferItem(StreamBufferItem *bufferItem)
bool StartThreadForInternalUpdates
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
Interface to a 3D positioning tool, video source, or generalized data stream.