PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusIntuitiveDaVinciTracker.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "igsioCommon.h"
9 #include "PlusConfigure.h"
11 
12 // VTK includes
13 #include <vtkImageData.h>
14 #include <vtkMath.h>
15 #include <vtkMatrix4x4.h>
16 
17 // OS includes
18 #include <ctype.h>
19 #include <float.h>
20 #include <iomanip>
21 #include <limits.h>
22 #include <math.h>
23 #include <time.h>
24 
25 // STL
26 #include <fstream>
27 #include <iostream>
28 #include <set>
29 
30 //----------------------------------------------------------------------------
31 
33 
34 //----------------------------------------------------------------------------
36  : vtkPlusDevice()
37  , DaVinci(new IntuitiveDaVinci())
38  , LastFrameNumber(0)
39  , FrameNumber(0)
40  , IpAddr("10.0.0.5")
41  , Port(5002)
42  , Password("")
43 #ifdef USE_DAVINCI_TIMESTAMPS
44  , TrackerTimeToSystemTimeSec(0.0)
45  , TrackerTimeToSystemTimeComputed(false)
46 #endif
47 {
48  this->StartThreadForInternalUpdates = false; // Callback based system
50  this->AcquisitionRate = 20;
51 }
52 
53 //----------------------------------------------------------------------------
55 {
56  this->StopRecording();
57  this->Disconnect();
58 
59  if (this->DaVinci != nullptr)
60  {
61  this->DaVinci->stop();
62  delete this->DaVinci;
63  this->DaVinci = nullptr;
64  }
65 }
66 
67 //----------------------------------------------------------------------------
68 void vtkPlusIntuitiveDaVinciTracker::PrintSelf(ostream& os, vtkIndent indent)
69 {
70 
71 }
72 
73 //----------------------------------------------------------------------------
75 {
76  return this->DaVinci->getLibraryVersion();
77 }
78 
79 //----------------------------------------------------------------------------
81 {
82  if (this->Connected)
83  {
84  LOG_ERROR("vtkPlusIntuitiveDaVinciTracker::Probe should not be called while the device is already initialized");
85  return PLUS_FAIL;
86  }
87 
88  if (this->DaVinci->connect() != ISI_SUCCESS)
89  {
90  LOG_ERROR("vtkPlusIntuitiveDaVinciTracker::Probe could not connect to the da Vinci!");
91  return PLUS_FAIL;
92  }
93 
94  // Get the list of manipulators for the da Vinci.
95  // If the list is zero, we've failed terribly.
96  // Possibly also check for names and verify we have what we expect.
97  std::vector<std::string> manipNames = this->DaVinci->getManipulatorNames();
98 
99  if (manipNames.size() == 0)
100  {
101  LOG_ERROR("Error in retrieving manipulator information. Zero manipulators found.");
102  return PLUS_FAIL;
103  }
104 
105  for (int i = 0; i < manipNames.size(); i++)
106  {
107  LOG_DEBUG("Manipulator " << i << " name: " << manipNames[i] << "\n");
108  }
109 
110  // TODO: Probe to see what we've specified in the XML file actually exists in the da Vinci
111 
112  this->DaVinci->stop();
113  this->DaVinci->disconnect();
114  return PLUS_SUCCESS;
115 }
116 
117 //----------------------------------------------------------------------------
119 {
120  if (!this->Connected)
121  {
122  LOG_ERROR("InternalStartRecording failed: da Vinci has not been initialized");
123  return PLUS_FAIL;
124  }
125 
126  if (!this->DaVinci->isConnected())
127  {
128  LOG_ERROR("InternalStartRecording failed: da Vinci is not connected");
129  return PLUS_FAIL;
130  }
131 
132  if (!this->DaVinci->start())
133  {
134  LOG_ERROR("InternalStartRecording: Unable to start streaming.");
135  return PLUS_FAIL;
136  }
137 
138  return PLUS_SUCCESS;
139 }
140 
141 //----------------------------------------------------------------------------
143 {
144  // Stop the stream and disconnect from the da Vinci.
145  this->DaVinci->stop();
146  return PLUS_SUCCESS;
147 }
148 
149 //----------------------------------------------------------------------------
151 {
152  LOG_TRACE("vtkPlusIntuitiveDaVinciTracker::ReadConfiguration");
153  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
154 
155  // Determine which manipulators we're interested in.
156  // Store those names for later, where we can then create the data source pointers.
157 
158  /* Because of how PLUS works when we create a vtkPlusDevice,
159  the XML file is already parsed. The parent class reads in the configuration
160  file, and finds all the data sources that are tools.
161 
162  It then parses the tool tags and adds them (if possible) to this device.
163 
164  See vtkPlusDevice.cxx : ReadConfiguration( ... )
165  */
166 
167  XML_READ_STRING_ATTRIBUTE_WARNING(IpAddr, deviceConfig);
168  XML_READ_SCALAR_ATTRIBUTE_WARNING(unsigned int, Port, deviceConfig);
169  XML_READ_STRING_ATTRIBUTE_WARNING(Password, deviceConfig);
170 
171  return PLUS_SUCCESS;
172 }
173 
174 //----------------------------------------------------------------------------
176 {
177  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(trackerConfig, rootConfigElement);
178 
179  XML_WRITE_STRING_ATTRIBUTE_IF_NOT_EMPTY(IpAddr, trackerConfig);
180  trackerConfig->SetIntAttribute("Port", this->Port);
181  XML_WRITE_STRING_ATTRIBUTE_IF_NOT_EMPTY(Password, trackerConfig);
182 
183  return PLUS_SUCCESS;
184 }
185 
186 //----------------------------------------------------------------------------
188 {
189  // Before trying to get to the da Vinci, let's see what was read in our XML config file.
190  // That is, what manipulators did we say we were interested in?
191  LOG_TRACE("vtkPlusIntuitiveDaVinciTracker::InternalConnect");
192 
193  if (this->Connected)
194  {
195  LOG_DEBUG("Already connected to da Vinci");
196  return PLUS_SUCCESS;
197  }
198 
199  // Try to connect a few different times. If at first you don't
200  // succeed, try again!
201  int connectionAttempts(0);
202  bool initCompleted(false);
203 
204  // Set our connection parameters obtained from the config file
206 
207  while (!initCompleted && connectionAttempts < MAX_ATTEMPTS)
208  {
209  if (this->DaVinci->connect() != 0)
210  {
211  LOG_DEBUG("Failed to connect to da Vinci. Retry: " << connectionAttempts);
212  vtkIGSIOAccurateTimer::Delay(1.0);
213  connectionAttempts++;
214  }
215 
216  initCompleted = true;
217  }
218 
219  if (connectionAttempts == MAX_ATTEMPTS)
220  {
221  LOG_ERROR("Error in initializing da Vinci");
222  return PLUS_FAIL;
223  }
224 
225  if (this->DaVinci->subscribe(NULL, vtkPlusIntuitiveDaVinciTrackerUtilities::streamCB, NULL, this) != ISI_SUCCESS)
226  {
227  LOG_ERROR("Error in subscribing to events and stream! Stream not started!");
228  return PLUS_FAIL;
229  }
230 
231 #ifdef USE_DAVINCI_TIMESTAMPS
232  this->TrackerTimeToSystemTimeSec = 0;
233  this->TrackerTimeToSystemTimeComputed = false;
234 #endif
235 
236  return PLUS_SUCCESS;
237 }
238 
239 //----------------------------------------------------------------------------
241 {
242  this->DaVinci->disconnect();
243 
244  return PLUS_SUCCESS;
245 }
246 
247 //----------------------------------------------------------------------------
249 {
250  return this->DaVinci;
251 }
252 
253 //----------------------------------------------------------------------------
254 void vtkPlusIntuitiveDaVinciTracker::StreamCallback(void)
255 {
256  if (!this->Connected)
257  {
258  LOG_ERROR("InternalUpdate failed: daVinci has not been initialized");
259  return;
260  }
261 
262  if (!this->Recording)
263  {
264  // Drop the frame, we're not recording.
265  LOG_DEBUG("Dropped frame: daVinci is not recording");
266  return;
267  }
268 
269  // Generate a frame number, as the tool does not provide a frame number.
270  // FrameNumber will be used in ToolTimeStampedUpdate for timestamp filtering
271  ++this->FrameNumber;
272 
273  // Setting the timestamp
274  const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
275 
276 #ifdef USE_DAVINCI_TIMESTAMPS
277  if (!this->TrackerTimeToSystemTimeComputed)
278  {
279  const double timeSystemSec = unfilteredTimestamp;
280  const double timeTrackerSec = this->DaVinci->mtGetLatestFrameTime();
281  this->TrackerTimeToSystemTimeSec = timeSystemSec - timeTrackerSec;
282  this->TrackerTimeToSystemTimeComputed = true;
283  }
284  const double timeTrackerSec = this->DaVinci->mtGetLatestFrameTime();
285  const double timeSystemSec = timeTrackerSec + this->TrackerTimeToSystemTimeSec;
286 #endif
287 
288  vtkNew<vtkMatrix4x4> transformMatrix;
289 
290  ISI_TRANSFORM* transform(NULL);
291  ISI_STREAM_FIELD stream_data;
292  for (DataSourceContainerIterator it = this->Tools.begin(); it != this->Tools.end(); ++it)
293  {
294  std::string toolName = it->second->GetPortName();
295 
296  ISI_MANIP_INDEX manipIndex = getManipIndexFromName(toolName);
297 
298  if (manipIndex == -1)
299  {
300  continue;
301  }
302 
303  bool inverseTransform(false);
304  if (toolName.find("_TIP") != std::string::npos)
305  {
306  // Get the tip transform for this manipulator
307  isi_get_stream_field(manipIndex, ISI_TIP_TRANSFORM, &stream_data);
308  transform = (ISI_TRANSFORM*) stream_data.data;
309  }
310  else if (toolName.find("_EYE_FRAME") != std::string::npos)
311  {
312  // Get the eye_frame (current camera frame w.r.t to world coordinates)
313  // It doesn't matter what the manipulator index is, the EYE FRAME will be the same fo
314  // all manipulators.
315  isi_get_reference_frame(ISI_PSM2, ISI_EYE_FRAME, transform);
316  inverseTransform = true; // This transform is the camera to world coordinates. We want our reference to be the inverse.
317  }
318 
319  // If we really don't have data, keep on keeping on.
320  if (transform == NULL)
321  {
322  continue;
323  }
324 
325  setVtkMatrixFromISITransform(*transformMatrix, transform);
326 
327  if (inverseTransform)
328  {
329  vtkMatrix4x4::Invert(transformMatrix, transformMatrix);
330  }
331 
332  std::ostringstream transformStream;
333  transformMatrix->Print(transformStream);
334  LOG_TRACE("Updating toolname: " << toolName << " with transform:\n\t" << transformStream << "\n");
335 
336 #ifdef USE_DAVINCI_TIMESTAMPS
337  this->ToolTimeStampedUpdateWithoutFiltering(it->second->GetSourceId(), transformMatrix, TOOL_OK, timeSystemSec, timeSystemSec);
338 #else
339  this->ToolTimeStampedUpdate(it->second->GetSourceId(), transformMatrix, TOOL_OK, this->FrameNumber, unfilteredTimestamp);
340 #endif
341  }
342 
343  LOG_TRACE("All subscribed fields from da Vinci have been updated");
344 }
345 
346 //----------------------------------------------------------------------------
347 ISI_MANIP_INDEX vtkPlusIntuitiveDaVinciTracker::getManipIndexFromName(const std::string& toolName)
348 {
349  ISI_MANIP_INDEX manipIndex = ISI_PSM1;
350 
351  toolName = toolName.substr(0, toolName.size() - 4);
352 
353  if (igsioCommon::IsEqualInsensitive("ISI_PSM1", toolName))
354  {
355  manipIndex = ISI_PSM1;
356  }
357  else if (igsioCommon::IsEqualInsensitive("ISI_PSM2", toolName))
358  {
359  manipIndex = ISI_PSM2;
360  }
361  else if (igsioCommon::IsEqualInsensitive("ISI_ECM", toolName))
362  {
363  manipIndex = ISI_ECM;
364  }
365  else if (igsioCommon::IsEqualInsensitive("ISI_MTML1", toolName))
366  {
367  manipIndex = ISI_MTML1;
368  }
369  else if (igsioCommon::IsEqualInsensitive("ISI_MTMR1", toolName))
370  {
371  manipIndex = ISI_MTMR1;
372  }
373  else if (igsioCommon::IsEqualInsensitive("ISI_PSM3", toolName))
374  {
375  manipIndex = ISI_PSM3;
376  }
377  else if (igsioCommon::IsEqualInsensitive("ISI_GANTRY", toolName))
378  {
379  manipIndex = ISI_GANTRY;
380  }
381  else if (igsioCommon::IsEqualInsensitive("ISI_MTML2", toolName))
382  {
383  manipIndex = ISI_MTML2;
384  }
385  else if (igsioCommon::IsEqualInsensitive("ISI_MTMR2", toolName))
386  {
387  manipIndex = ISI_MTMR2;
388  }
389  else if (igsioCommon::IsEqualInsensitive("ISI_CONSOLE1", toolName))
390  {
391  manipIndex = ISI_CONSOLE1;
392  }
393  else if (igsioCommon::IsEqualInsensitive("ISI_CONSOLE2", toolName))
394  {
395  manipIndex = ISI_CONSOLE2;
396  }
397  else if (igsioCommon::IsEqualInsensitive("ISI_CORE", toolName))
398  {
399  manipIndex = ISI_CORE;
400  }
401  else
402  {
403  LOG_DEBUG("Could not set manipIndex. Defaulting to PSM1");
404  }
405 
406  return manipIndex;
407 }
408 
409 //----------------------------------------------------------------------------
410 void vtkPlusIntuitiveDaVinciTracker::setVtkMatrixFromISITransform(vtkMatrix4x4& destVtkMatrix, ISI_TRANSFORM* srcIsiMatrix)
411 {
412  destVtkMatrix->Identity();
413 
414  // Let's VERY EXPLCITLY copy over the values.
415  destVtkMatrix.SetElement(0, 0, srcIsiMatrix->rot.row0.x);
416  destVtkMatrix.SetElement(1, 0, srcIsiMatrix->rot.row0.y);
417  destVtkMatrix.SetElement(2, 0, srcIsiMatrix->rot.row0.z);
418  destVtkMatrix.SetElement(3, 0, 0);
419 
420  destVtkMatrix.SetElement(0, 1, srcIsiMatrix->rot.row1.x);
421  destVtkMatrix.SetElement(1, 1, srcIsiMatrix->rot.row1.y);
422  destVtkMatrix.SetElement(2, 1, srcIsiMatrix->rot.row1.z);
423  destVtkMatrix.SetElement(3, 1, 0);
424 
425  destVtkMatrix.SetElement(0, 2, srcIsiMatrix->rot.row2.x);
426  destVtkMatrix.SetElement(1, 2, srcIsiMatrix->rot.row2.y);
427  destVtkMatrix.SetElement(2, 2, srcIsiMatrix->rot.row2.z);
428  destVtkMatrix.SetElement(3, 2, 0);
429 
430  destVtkMatrix.SetElement(0, 3, srcIsiMatrix->pos.x);
431  destVtkMatrix.SetElement(1, 3, srcIsiMatrix->pos.y);
432  destVtkMatrix.SetElement(2, 3, srcIsiMatrix->pos.z);
433  destVtkMatrix.SetElement(3, 3, 1);
434 
435  return;
436 }
437 
439 {
440  //----------------------------------------------------------------------------
441  void ISICALLBACK eventCB(ISI_MANIP_INDEX mid, ISI_EVENT_ID event_id, ISI_INT args[ISI_NUM_EVENT_ARGS], void* userdata)
442  {
443  LOG_INFO(isi_get_event_timestamp(mid, event_id) << " mid: " << isi_get_manip_name(mid) << ",\tevent: " << isi_get_event_name(event_id) << ", args: (" << args[0] << " " << args[1] << " " << args[2] << " " << args[3] << ")");
444  }
445 
446  //----------------------------------------------------------------------------
447  void ISICALLBACK streamCB(void* userData)
448  {
449  vtkPlusIntuitiveDaVinciTracker* trackerInstance = reinterpret_cast<vtkPlusIntuitiveDaVinciTracker*>(userData);
450  if (trackerInstance)
451  {
452  trackerInstance->StreamCallback();
453  }
454  }
455 };
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
void ISICALLBACK eventCB(ISI_MANIP_INDEX mid, ISI_EVENT_ID event_id, ISI_INT args[ISI_NUM_EVENT_ARGS], void *userdata)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
virtual PlusStatus ToolTimeStampedUpdateWithoutFiltering(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, double unfilteredtimestamp, double filteredtimestamp, const igsioFieldMapType *customFields=NULL)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
void setHostInfo(const std::string ip, const unsigned int port, const std::string pass)
virtual PlusStatus ToolTimeStampedUpdate(const std::string &aToolSourceId, vtkMatrix4x4 *matrix, ToolStatus status, unsigned long frameNumber, double unfilteredtimestamp, const igsioFieldMapType *customFields=NULL)
bool RequirePortNameInDeviceSetConfiguration
for i
double AcquisitionRate
#define PLUS_FAIL
Definition: PlusCommon.h:43
DataSourceContainer Tools
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *rootConfigElement)
virtual PlusStatus Disconnect()
ISI_STATUS disconnect()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
std::vector< std::string > getManipulatorNames()
vtkStandardNewMacro(vtkPlusIntuitiveDaVinciTracker)
ISI_STATUS subscribe(ISI_EVENT_CALLBACK eCB, ISI_STREAM_CALLBACK sCB, void *eventUserData, void *streamUserData)
virtual PlusStatus StopRecording()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
ISI_STATUS connect()
DataSourceContainer::iterator DataSourceContainerIterator
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *rootConfigElement)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
bool StartThreadForInternalUpdates
std::string getLibraryVersion()