Skip to content

Commit

Permalink
Add 3D support to Polhemus tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
JensAhrens committed Jun 15, 2023
1 parent bb6a47e commit 7afd342
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 49 deletions.
2 changes: 2 additions & 0 deletions doc/manual/browser-gui.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _browser-based_gui:

Browser-based GUI
=================

Expand Down
10 changes: 10 additions & 0 deletions doc/manual/operation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ You can calibrate the tracker while the SSR is running by pressing
``Return``. The instantaneous orientation will then be interpreted as
straight forward, i.e. upwards on the screen (:math:`\alpha = 90^\circ`\ ).

SSR is progressively (and silently) moving from 2D scenes to 3D scenes. The
:ref:`binaural renderer<binaural_renderer>` can handle head tracking about all
three axes of rotation if the HRIRs are provided in SOFA. We recommend using
the :ref:`browser-based GUI<browser-based_gui>` to monitor the tracking as the
built-in GUI only visualizes tracking along the azimuth.

.. _prep_isense:

Preparing InterSense InertiaCube3
Expand Down Expand Up @@ -302,6 +308,10 @@ or so.
If you want to disable this tracker, use ``./configure --disable-polhemus``
and recompile.

If you are using head tracking about all three axes of rotation, make sure
that the tracking sensor is mounted on the headphones such that the cable
leaves the sensor towards the left relative to the look direction of the user.

Preparing VRPN
^^^^^^^^^^^^^^

Expand Down
7 changes: 6 additions & 1 deletion doc/manual/renderers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ the outside of the listener's head to the inside.
SSR uses HRIRs with an angular resolution of :math:`1^\circ`\ . Thus,
the HRIR file contains 720 impulse responses (360 for each ear) stored
as a 720-channel .wav-file. The HRIRs all have to be of equal length and
have to be arranged in the following order:
have to be arranged in the following order [#fnsofa]_:

- 1st channel: left ear, virtual source position :math:`0^\circ`

Expand Down Expand Up @@ -330,6 +330,11 @@ the HRIRs. By choosing shorter frames and thus using partitioned
convolution the system latency is reduced but computational load is
increased.

.. [#fnsofa] Note that the binaural renderer has the currently hidden and
undocumented feature of being able to read HRIRs in `SOFA
<https://www.sofaconventions.org/>`_. It supports head tracking
about all three axes of rotation in this case.
The HRIR sets shipped with SSR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
36 changes: 22 additions & 14 deletions src/gui/qopenglplotter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ ssr::QOpenGLPlotter::paintGL()
_draw_reference();

_draw_objects();

_draw_rubber_band();
}

Expand Down Expand Up @@ -362,8 +362,10 @@ void ssr::QOpenGLPlotter::_draw_reference()
glPushMatrix();

// translate according to reference position
glTranslatef(_scene.get_reference().position.x,
_scene.get_reference().position.y, 0.0f);
glTranslatef(_scene.get_reference().position.x +
_scene.get_reference_offset().position.x,
_scene.get_reference().position.y +
_scene.get_reference_offset().position.y, 0.0f);

glPushMatrix();

Expand All @@ -383,7 +385,9 @@ void ssr::QOpenGLPlotter::_draw_reference()
glTranslatef(0.03f, -0.03f, 0.0f);

// rotate according to reference position
glRotatef(_scene.get_reference().orientation.azimuth, 0.0f, 0.0f, 1.0f);
glRotatef(_scene.get_reference().orientation.azimuth +
_scene.get_reference_offset().orientation.azimuth
, 0.0f, 0.0f, 1.0f);

glBindTexture(GL_TEXTURE_2D, _listener_shadow_texture);

Expand All @@ -397,7 +401,9 @@ void ssr::QOpenGLPlotter::_draw_reference()
glPopMatrix();

// rotate according to reference position
glRotatef(_scene.get_reference().orientation.azimuth, 0.0f, 0.0f, 1.0f);
glRotatef(_scene.get_reference().orientation.azimuth +
_scene.get_reference_offset().orientation.azimuth
,0.0f, 0.0f, 1.0f);

glBindTexture(GL_TEXTURE_2D, _listener_texture);

Expand All @@ -414,7 +420,8 @@ void ssr::QOpenGLPlotter::_draw_reference()
else
{
// rotate according to reference position
glRotatef(_scene.get_reference().orientation.azimuth, 0.0f, 0.0f, 1.0f);
glRotatef(_scene.get_reference().orientation.azimuth +
_scene.get_reference_offset().orientation.azimuth, 0.0f, 0.0f, 1.0f);

// background color
glColor3f(BACKGROUNDCOLOR);
Expand Down Expand Up @@ -448,8 +455,9 @@ void ssr::QOpenGLPlotter::_draw_reference()
// rotate/translate according to reference offset
glTranslatef(_scene.get_reference_offset().position.x
, _scene.get_reference_offset().position.y, 0.0f);
glRotatef(_scene.get_reference_offset().orientation.azimuth
, 0.0f, 0.0f, 1.0f);
glRotatef(_scene.get_reference().orientation.azimuth +
_scene.get_reference_offset().orientation.azimuth
, 0.0f, 0.0f, 1.0f);

// draw cross (showing the reference offset)
glBegin(GL_LINES);
Expand Down Expand Up @@ -491,7 +499,7 @@ void ssr::QOpenGLPlotter::_draw_objects()

std::vector<float> output_levels;


if (_selected_sources_map.size() > 0)
{
output_levels = _scene.get_source(_selected_sources_map.rbegin()->second).output_levels;
Expand Down Expand Up @@ -1044,7 +1052,7 @@ void ssr::QOpenGLPlotter::_select_source(int source, bool add_to_selection)

// if source does not exist
if (source > static_cast<int>(source_buffer_list.size()))
{
{
_id_of_last_clicked_source = 0;
return;
}
Expand All @@ -1053,13 +1061,13 @@ void ssr::QOpenGLPlotter::_select_source(int source, bool add_to_selection)

// iterate to source
for (int n = 1; n < source; n++) i++;

// make its id directly available
_id_of_last_clicked_source = i->id;

// store source and its id
_selected_sources_map[source] = _id_of_last_clicked_source; // TODO

}
else if (!_alt_pressed)
{
Expand All @@ -1068,7 +1076,7 @@ void ssr::QOpenGLPlotter::_select_source(int source, bool add_to_selection)
}
// if source is already selected then deselect it
else if (_alt_pressed) _deselect_source(source);

}

void ssr::QOpenGLPlotter::_select_all_sources()
Expand Down
45 changes: 30 additions & 15 deletions src/trackerpolhemus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
#include <chrono> // std::chrono::milliseconds

#include "api.h" // for Publisher
#include "legacy_orientation.h" // for Orientation
#include "trackerpolhemus.h"
#include "ssr_global.h"
#include "apf/stringtools.h"
Expand All @@ -47,7 +46,7 @@ ssr::TrackerPolhemus::TrackerPolhemus(api::Publisher& controller
, const std::string& type, const std::string& ports)
: Tracker()
, _controller(controller)
, _az_corr(0.0f)
, _corr_quat()
, _stop_thread(false)
{
if (ports == "")
Expand Down Expand Up @@ -192,7 +191,7 @@ ssr::TrackerPolhemus::_open_serial_port(const char *portname)
void
ssr::TrackerPolhemus::calibrate()
{
_az_corr = _current_data.azimuth;
_corr_quat = inverse(_current_quat);
}

void
Expand Down Expand Up @@ -236,7 +235,7 @@ ssr::TrackerPolhemus::_thread()

if (error < 1)
{
SSR_ERROR("Can not read from serial port. Stopping Polhemus tracker.");
SSR_ERROR("Cannot read from serial port. Stopping Polhemus tracker.");
}

if ((error = read(_tracker_port, &c, 1)))
Expand All @@ -245,13 +244,13 @@ ssr::TrackerPolhemus::_thread()
}
else
{
SSR_ERROR("Can not read from serial port.");
SSR_ERROR("Cannot read from serial port.");
}
}

if (line.size() != _line_size)
{
_current_data.azimuth = 0.0f;
// simply keep whatever is store in _current_quat
continue;
}

Expand Down Expand Up @@ -282,16 +281,32 @@ ssr::TrackerPolhemus::_thread()
// sockets are available and each of the 6 degrees of freedom are represented by
// 9 bytes, leading to a total of 60 ASCII bytes.

// extract data
lineparse >> _current_data.header
>> _current_data.x
>> _current_data.y
>> _current_data.z
>> _current_data.azimuth
>> _current_data.elevation
>> _current_data.roll;
float header;
float x;
float y;
float z;
float azimuth;
float elevation;
float roll;

// extract data
lineparse >> header
>> x
>> y
>> z
>> azimuth
>> elevation
>> roll;

// convert to quaternion (-azimuth because the tracker assumes that positive
// z is downwards; rotation by 90 deg because we assume that the sensor is
// mounted such that the cable goes to the left relative to the user's
// orientation)
_current_quat = angles2quat(-azimuth, elevation, roll)
* angles2quat(90, 0, 0);

// apply calibration
_controller.take_control()->reference_rotation_offset(
Orientation(-_current_data.azimuth + _az_corr));
ssr::quat(_corr_quat * _current_quat));
};
}
22 changes: 3 additions & 19 deletions src/trackerpolhemus.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <stdexcept> // for std::runtime_error

#include "tracker.h"
#include "geometry.h"

namespace ssr
{
Expand All @@ -62,31 +63,14 @@ class TrackerPolhemus : public Tracker
TrackerPolhemus(api::Publisher& controller, const std::string& type
, const std::string& ports);

struct tracker_data_t
{
float header;
float x;
float y;
float z;
float azimuth;
float elevation;
float roll;

// contructor
tracker_data_t()
: header(0.0f), x(0.0f), y(0.0f), z(0.0f)
, azimuth(0.0f), elevation(0.0f), roll(0.0f)
{}
};

api::Publisher& _controller;

tracker_data_t _current_data;
ssr::quat _current_quat;

int _tracker_port;
int _open_serial_port(const char *portname);

float _az_corr; ///< correction of the azimuth due to calibration
ssr::quat _corr_quat; ///< correction of the orientation due to calibration

std::string::size_type _line_size;

Expand Down

0 comments on commit 7afd342

Please sign in to comment.