Commit f64959b98097c05e706e81faa74a9aa67820b144
Exists in
master
Merge branch 'master' into multimodal_tracking
# Conflicts: # invesalius/constants.py
Showing
7 changed files
with
72 additions
and
33 deletions
Show diff stats
invesalius/constants.py
... | ... | @@ -830,11 +830,12 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit |
830 | 830 | |
831 | 831 | MARKER_FILE_MAGICK_STRING = "##INVESALIUS3_MARKER_FILE_" |
832 | 832 | CURRENT_MARKER_FILE_VERSION = 0 |
833 | -WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss") | |
833 | +WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss") | |
834 | 834 | |
835 | 835 | # Serial port |
836 | 836 | BAUD_RATES = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200] |
837 | 837 | BAUD_RATE_DEFAULT_SELECTION = 4 |
838 | +PULSE_DURATION_IN_MILLISECONDS = 0.2 | |
838 | 839 | |
839 | 840 | #Robot |
840 | 841 | ROBOT_ElFIN_IP = ['143.107.220.251', '169.254.153.251', '127.0.0.1'] |
... | ... | @@ -843,4 +844,3 @@ ROBOT_MOTIONS = {"normal": 0, "linear out": 1, "arc": 2} |
843 | 844 | ROBOT_HEAD_VELOCITY_THRESHOLD = 10 |
844 | 845 | ROBOT_ARC_THRESHOLD_DISTANCE = 100 |
845 | 846 | ROBOT_VERSOR_SCALE_FACTOR = 70 |
846 | - | ... | ... |
invesalius/data/serial_port_connection.py
... | ... | @@ -22,12 +22,12 @@ import threading |
22 | 22 | import time |
23 | 23 | |
24 | 24 | import wx |
25 | + | |
26 | +from invesalius import constants | |
25 | 27 | from invesalius.pubsub import pub as Publisher |
26 | 28 | |
27 | 29 | |
28 | 30 | class SerialPortConnection(threading.Thread): |
29 | - BINARY_PULSE = b'\x01' | |
30 | - | |
31 | 31 | def __init__(self, com_port, baud_rate, serial_port_queue, event, sleep_nav): |
32 | 32 | """ |
33 | 33 | Thread created to communicate using the serial port to interact with software during neuronavigation. |
... | ... | @@ -65,7 +65,7 @@ class SerialPortConnection(threading.Thread): |
65 | 65 | |
66 | 66 | def SendPulse(self): |
67 | 67 | try: |
68 | - self.connection.write(self.BINARY_PULSE) | |
68 | + self.connection.send_break(constants.PULSE_DURATION_IN_MILLISECONDS / 1000) | |
69 | 69 | Publisher.sendMessage('Serial port pulse triggered') |
70 | 70 | except: |
71 | 71 | print("Error: Serial port could not be written into.") | ... | ... |
invesalius/data/trackers.py
... | ... | @@ -301,9 +301,11 @@ def PlhSerialConnection(tracker_id): |
301 | 301 | trck_init = None |
302 | 302 | dlg_port = dlg.SetCOMPort(select_baud_rate=False) |
303 | 303 | if dlg_port.ShowModal() == ID_OK: |
304 | - com_port = dlg_port.GetValue() | |
304 | + com_port = dlg_port.GetCOMPort() | |
305 | + baud_rate = 115200 | |
306 | + | |
305 | 307 | try: |
306 | - trck_init = serial.Serial(com_port, baudrate=115200, timeout=0.03) | |
308 | + trck_init = serial.Serial(com_port, baudrate=baud_rate, timeout=0.03) | |
307 | 309 | |
308 | 310 | if tracker_id == 2: |
309 | 311 | # Polhemus FASTRAK needs configurations first | ... | ... |
invesalius/data/viewer_volume.py
... | ... | @@ -726,9 +726,13 @@ class Viewer(wx.Panel): |
726 | 726 | self.distthreshold = dist_threshold |
727 | 727 | |
728 | 728 | def ActivateTargetMode(self, evt=None, target_mode=None): |
729 | + | |
729 | 730 | vtk_colors = vtk.vtkNamedColors() |
730 | 731 | self.target_mode = target_mode |
731 | 732 | if self.target_coord and self.target_mode: |
733 | + if self.actor_peel: | |
734 | + self.object_orientation_torus_actor.SetVisibility(0) | |
735 | + self.obj_projection_arrow_actor.SetVisibility(0) | |
732 | 736 | self.CreateTargetAim() |
733 | 737 | |
734 | 738 | # Create a line |
... | ... | @@ -831,6 +835,9 @@ class Viewer(wx.Panel): |
831 | 835 | |
832 | 836 | else: |
833 | 837 | self.DisableCoilTracker() |
838 | + if self.actor_peel: | |
839 | + self.object_orientation_torus_actor.SetVisibility(1) | |
840 | + self.obj_projection_arrow_actor.SetVisibility(1) | |
834 | 841 | |
835 | 842 | def OnUpdateObjectTargetGuide(self, m_img, coord): |
836 | 843 | ... | ... |
invesalius/gui/dialogs.py
... | ... | @@ -4809,15 +4809,16 @@ class SetCOMPort(wx.Dialog): |
4809 | 4809 | |
4810 | 4810 | self.CenterOnParent() |
4811 | 4811 | |
4812 | - def GetValue(self): | |
4812 | + def GetCOMPort(self): | |
4813 | 4813 | com_port = self.com_port_dropdown.GetString(self.com_port_dropdown.GetSelection()) |
4814 | + return com_port | |
4814 | 4815 | |
4815 | - if self.select_baud_rate: | |
4816 | - baud_rate = self.baud_rate_dropdown.GetString(self.baud_rate_dropdown.GetSelection()) | |
4817 | - else: | |
4818 | - baud_rate = None | |
4816 | + def GetBaudRate(self): | |
4817 | + if not self.select_baud_rate: | |
4818 | + return None | |
4819 | 4819 | |
4820 | - return com_port, baud_rate | |
4820 | + baud_rate = self.baud_rate_dropdown.GetString(self.baud_rate_dropdown.GetSelection()) | |
4821 | + return baud_rate | |
4821 | 4822 | |
4822 | 4823 | |
4823 | 4824 | class ManualWWWLDialog(wx.Dialog): | ... | ... |
invesalius/gui/task_navigator.py
... | ... | @@ -305,7 +305,7 @@ class InnerFoldPanel(wx.Panel): |
305 | 305 | ctrl.SetValue(False) |
306 | 306 | return |
307 | 307 | |
308 | - com_port = dlg_port.GetValue() | |
308 | + com_port = dlg_port.GetCOMPort() | |
309 | 309 | baud_rate = 115200 |
310 | 310 | |
311 | 311 | Publisher.sendMessage('Update serial port', serial_port_in_use=True, com_port=com_port, baud_rate=baud_rate) |
... | ... | @@ -410,16 +410,10 @@ class NeuronavigationPanel(wx.Panel): |
410 | 410 | |
411 | 411 | self.btns_set_fiducial[n + 3] = ctrl |
412 | 412 | |
413 | - # TODO: Find a better allignment between FRE, text and navigate button | |
414 | - txt_fre = wx.StaticText(self, -1, _('FRE:')) | |
415 | - txt_icp = wx.StaticText(self, -1, _('Refine:')) | |
413 | + # TODO: Find a better alignment between FRE, text and navigate button | |
416 | 414 | |
417 | - if pedal_connection is not None and pedal_connection.in_use: | |
418 | - txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:')) | |
419 | - else: | |
420 | - txt_pedal_pressed = None | |
421 | - | |
422 | - # Fiducial registration error text box | |
415 | + # Fiducial registration error text and checkbox | |
416 | + txt_fre = wx.StaticText(self, -1, _('FRE:')) | |
423 | 417 | tooltip = wx.ToolTip(_("Fiducial registration error")) |
424 | 418 | txtctrl_fre = wx.TextCtrl(self, value="", size=wx.Size(60, -1), style=wx.TE_CENTRE) |
425 | 419 | txtctrl_fre.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD)) |
... | ... | @@ -434,6 +428,8 @@ class NeuronavigationPanel(wx.Panel): |
434 | 428 | btn_nav.SetToolTip(tooltip) |
435 | 429 | btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav)) |
436 | 430 | |
431 | + # "Refine" text and checkbox | |
432 | + txt_icp = wx.StaticText(self, -1, _('Refine:')) | |
437 | 433 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) |
438 | 434 | checkbox_icp = wx.CheckBox(self, -1, _(' ')) |
439 | 435 | checkbox_icp.SetValue(False) |
... | ... | @@ -442,8 +438,9 @@ class NeuronavigationPanel(wx.Panel): |
442 | 438 | checkbox_icp.SetToolTip(tooltip) |
443 | 439 | self.checkbox_icp = checkbox_icp |
444 | 440 | |
445 | - # An indicator for pedal trigger | |
441 | + # "Pedal pressed" text and an indicator (checkbox) for pedal press | |
446 | 442 | if pedal_connection is not None and pedal_connection.in_use: |
443 | + txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:')) | |
447 | 444 | tooltip = wx.ToolTip(_(u"Is the pedal pressed")) |
448 | 445 | checkbox_pedal_pressed = wx.CheckBox(self, -1, _(' ')) |
449 | 446 | checkbox_pedal_pressed.SetValue(False) |
... | ... | @@ -454,15 +451,27 @@ class NeuronavigationPanel(wx.Panel): |
454 | 451 | |
455 | 452 | self.checkbox_pedal_pressed = checkbox_pedal_pressed |
456 | 453 | else: |
454 | + txt_pedal_pressed = None | |
457 | 455 | self.checkbox_pedal_pressed = None |
458 | 456 | |
457 | + # "Lock to target" text and checkbox | |
458 | + tooltip = wx.ToolTip(_(u"Allow triggering stimulation pulse only if the coil is at the target")) | |
459 | + lock_to_target_text = wx.StaticText(self, -1, _('Lock to target:')) | |
460 | + lock_to_target_checkbox = wx.CheckBox(self, -1, _(' ')) | |
461 | + lock_to_target_checkbox.SetValue(False) | |
462 | + lock_to_target_checkbox.Enable(False) | |
463 | + lock_to_target_checkbox.Bind(wx.EVT_CHECKBOX, partial(self.OnLockToTargetCheckbox, ctrl=lock_to_target_checkbox)) | |
464 | + lock_to_target_checkbox.SetToolTip(tooltip) | |
465 | + | |
466 | + self.lock_to_target_checkbox = lock_to_target_checkbox | |
467 | + | |
459 | 468 | # Image and tracker coordinates number controls |
460 | 469 | for m in range(len(self.btns_set_fiducial)): |
461 | 470 | for n in range(3): |
462 | 471 | self.numctrls_fiducial[m].append( |
463 | 472 | wx.lib.masked.numctrl.NumCtrl(parent=self, integerWidth=4, fractionWidth=1)) |
464 | 473 | |
465 | - # Sizer to group all GUI objects | |
474 | + # Sizers to group all GUI objects | |
466 | 475 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) |
467 | 476 | choice_sizer.AddMany([(select_tracker_elem, wx.LEFT), |
468 | 477 | (choice_ref, wx.RIGHT)]) |
... | ... | @@ -483,10 +492,13 @@ class NeuronavigationPanel(wx.Panel): |
483 | 492 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
484 | 493 | (checkbox_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) |
485 | 494 | |
486 | - pedal_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) | |
487 | - if HAS_PEDAL_CONNECTION and pedal_connection.in_use: | |
488 | - pedal_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | |
489 | - (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | |
495 | + checkboxes_sizer = wx.FlexGridSizer(rows=1, cols=4, hgap=5, vgap=5) | |
496 | + checkboxes_sizer.AddMany([(lock_to_target_text, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | |
497 | + (lock_to_target_checkbox, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | |
498 | + | |
499 | + if pedal_connection is not None and pedal_connection.in_use: | |
500 | + checkboxes_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | |
501 | + (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) | |
490 | 502 | |
491 | 503 | group_sizer = wx.FlexGridSizer(rows=10, cols=1, hgap=5, vgap=5) |
492 | 504 | group_sizer.AddGrowableCol(0, 1) |
... | ... | @@ -497,7 +509,7 @@ class NeuronavigationPanel(wx.Panel): |
497 | 509 | group_sizer.AddMany([(choice_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
498 | 510 | (coord_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
499 | 511 | (nav_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL), |
500 | - (pedal_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)]) | |
512 | + (checkboxes_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)]) | |
501 | 513 | |
502 | 514 | main_sizer = wx.BoxSizer(wx.HORIZONTAL) |
503 | 515 | main_sizer.Add(group_sizer, 1)# wx.ALIGN_CENTER_HORIZONTAL, 10) |
... | ... | @@ -575,7 +587,6 @@ class NeuronavigationPanel(wx.Panel): |
575 | 587 | self.ResetICP() |
576 | 588 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) |
577 | 589 | |
578 | - | |
579 | 590 | def UpdatePeelVisualization(self, data): |
580 | 591 | self.navigation.peel_loaded = data |
581 | 592 | |
... | ... | @@ -614,6 +625,10 @@ class NeuronavigationPanel(wx.Panel): |
614 | 625 | def UpdateTarget(self, coord): |
615 | 626 | self.navigation.target = coord |
616 | 627 | |
628 | + self.lock_to_target_checkbox.Enable(True) | |
629 | + self.lock_to_target_checkbox.SetValue(True) | |
630 | + self.navigation.SetLockToTarget(True) | |
631 | + | |
617 | 632 | def EnableACT(self, data): |
618 | 633 | self.navigation.enable_act = data |
619 | 634 | |
... | ... | @@ -644,6 +659,10 @@ class NeuronavigationPanel(wx.Panel): |
644 | 659 | self.ResetICP() |
645 | 660 | self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre) |
646 | 661 | |
662 | + def OnLockToTargetCheckbox(self, evt, ctrl): | |
663 | + value = ctrl.GetValue() | |
664 | + self.navigation.SetLockToTarget(value) | |
665 | + | |
647 | 666 | def OnChooseTracker(self, evt, ctrl): |
648 | 667 | Publisher.sendMessage('Update status text in GUI', |
649 | 668 | label=_("Configuring tracker ...")) |
... | ... | @@ -1394,7 +1413,7 @@ class MarkersPanel(wx.Panel): |
1394 | 1413 | |
1395 | 1414 | @staticmethod |
1396 | 1415 | def __list_fiducial_labels(): |
1397 | - """Return the list of marker labels denoting fucials.""" | |
1416 | + """Return the list of marker labels denoting fiducials.""" | |
1398 | 1417 | return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS))) |
1399 | 1418 | |
1400 | 1419 | def UpdateCurrentCoord(self, position): | ... | ... |
invesalius/navigation/navigation.py
... | ... | @@ -177,6 +177,7 @@ class Navigation(): |
177 | 177 | self.serial_port_connection = None |
178 | 178 | |
179 | 179 | # During navigation |
180 | + self.lock_to_target = False | |
180 | 181 | self.coil_at_target = False |
181 | 182 | |
182 | 183 | self.__bind_events() |
... | ... | @@ -197,6 +198,9 @@ class Navigation(): |
197 | 198 | self.com_port = com_port |
198 | 199 | self.baud_rate = baud_rate |
199 | 200 | |
201 | + def SetLockToTarget(self, value): | |
202 | + self.lock_to_target = value | |
203 | + | |
200 | 204 | def SetReferenceMode(self, value): |
201 | 205 | self.ref_mode_id = value |
202 | 206 | |
... | ... | @@ -223,7 +227,13 @@ class Navigation(): |
223 | 227 | return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD |
224 | 228 | |
225 | 229 | def PedalStateChanged(self, state): |
226 | - if state is True and self.coil_at_target and self.serial_port_in_use: | |
230 | + if not self.serial_port_in_use: | |
231 | + return | |
232 | + | |
233 | + permission_to_stimulate = (self.lock_to_target and self.coil_at_target) or \ | |
234 | + not self.lock_to_target | |
235 | + | |
236 | + if state and permission_to_stimulate: | |
227 | 237 | self.serial_port_connection.SendPulse() |
228 | 238 | |
229 | 239 | def StartNavigation(self, tracker): | ... | ... |