Added OutOfRangeDataStrategy parameter to Controller Settings

The openvr SDK provides a way to gauge the quality of tracking on a given device via the eTrackingResult enum.

* Drop - Only Running_OK is considered valid, all other eTrackingResults will return invalid poses.
* Freeze - Only Running_OK is considered valid, but other valid TrackingResults will return the last Running_OK pose.
  In esseces this will freeze the puck in place at the last good value.
* None - All valid eTrackingResults will be valid, including OutOfRange and Calibrating results.  This is the default.
This commit is contained in:
Anthony Thibault 2018-09-19 16:08:16 -07:00
parent d15cc86735
commit 7777f3edd0
4 changed files with 118 additions and 39 deletions
interface/resources
controllers
qml/hifi/tablet
plugins/openvr/src

View file

@ -51,17 +51,8 @@
{ "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" },
{ "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" },
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand",
"filters" : [{"type" : "accelerationLimiter",
"rotationAccelerationLimit" : 4000.0, "rotationDecelerationLimit" : 8000.0,
"translationAccelerationLimit": 200.0, "translationDecelerationLimit": 400.0}]
},
{ "from": "Vive.RightHand", "to": "Standard.RightHand",
"filters" : [{"type" : "accelerationLimiter",
"rotationAccelerationLimit" : 2000.0, "rotationDecelerationLimit" : 4000.0,
"translationAccelerationLimit": 100.0, "translationDecelerationLimit": 200.0}]
},
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand"},
{ "from": "Vive.RightHand", "to": "Standard.RightHand"},
{
"from": "Vive.LeftFoot", "to" : "Standard.LeftFoot",

View file

@ -822,11 +822,44 @@ Flickable {
}
}
Row {
id: outOfRangeDataStrategyRow
anchors.top: viveInDesktop.bottom
anchors.topMargin: 5
anchors.left: openVrConfiguration.left
anchors.leftMargin: leftMargin + 10
spacing: 15
RalewayRegular {
id: outOfRangeDataStrategyLabel
size: 12
text: "Out Of Range Data Strategy:"
color: hifi.colors.lightGrayText
topPadding: 5
}
HifiControls.ComboBox {
id: outOfRangeDataStrategyComboBox
height: 25
width: 100
editable: true
colorScheme: hifi.colorSchemes.dark
model: ["None", "Freeze", "Drop"]
label: ""
onCurrentIndexChanged: {
sendConfigurationSettings();
}
}
}
RalewayBold {
id: viveDesktopText
size: 10
size: 12
text: "Use " + stack.selectedPlugin + " devices in desktop mode"
color: hifi.colors.white
color: hifi.colors.lightGrayText
anchors {
left: viveInDesktop.right
@ -946,6 +979,7 @@ Flickable {
viveInDesktop.checked = desktopMode;
hmdInDesktop.checked = hmdDesktopPosition;
outOfRangeDataStrategyComboBox.currentIndex = outOfRangeDataStrategyComboBox.model.indexOf(settings.outOfRangeDataStrategy);
initializeButtonState();
updateCalibrationText();
@ -1107,7 +1141,8 @@ Flickable {
"armCircumference": armCircumference.realValue,
"shoulderWidth": shoulderWidth.realValue,
"desktopMode": viveInDesktop.checked,
"hmdDesktopTracking": hmdInDesktop.checked
"hmdDesktopTracking": hmdInDesktop.checked,
"outOfRangeDataStrategy": outOfRangeDataStrategyComboBox.model[outOfRangeDataStrategyComboBox.currentIndex]
}
return settingsObject;

View file

@ -129,6 +129,28 @@ static glm::mat4 calculateResetMat() {
return glm::mat4();
}
static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) {
switch (strategy) {
default:
case ViveControllerManager::OutOfRangeDataStrategy::None:
return "None";
case ViveControllerManager::OutOfRangeDataStrategy::Freeze:
return "Freeze";
case ViveControllerManager::OutOfRangeDataStrategy::Drop:
return "Drop";
}
}
static ViveControllerManager::OutOfRangeDataStrategy stringToOutOfRangeDataStrategy(const QString& string) {
if (string == "Drop") {
return ViveControllerManager::OutOfRangeDataStrategy::Drop;
} else if (string == "Freeze") {
return ViveControllerManager::OutOfRangeDataStrategy::Freeze;
} else {
return ViveControllerManager::OutOfRangeDataStrategy::None;
}
}
bool ViveControllerManager::isDesktopMode() {
if (_container) {
return !_container->getActiveDisplayPlugin()->isHmd();
@ -288,8 +310,10 @@ void ViveControllerManager::loadSettings() {
if (_inputDevice) {
const double DEFAULT_ARM_CIRCUMFERENCE = 0.33;
const double DEFAULT_SHOULDER_WIDTH = 0.48;
const QString DEFAULT_OUT_OF_RANGE_STRATEGY = "None";
_inputDevice->_armCircumference = settings.value("armCircumference", QVariant(DEFAULT_ARM_CIRCUMFERENCE)).toDouble();
_inputDevice->_shoulderWidth = settings.value("shoulderWidth", QVariant(DEFAULT_SHOULDER_WIDTH)).toDouble();
_inputDevice->_outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(settings.value("outOfRangeDataStrategy", QVariant(DEFAULT_OUT_OF_RANGE_STRATEGY)).toString());
}
}
settings.endGroup();
@ -303,6 +327,7 @@ void ViveControllerManager::saveSettings() const {
if (_inputDevice) {
settings.setValue(QString("armCircumference"), _inputDevice->_armCircumference);
settings.setValue(QString("shoulderWidth"), _inputDevice->_shoulderWidth);
settings.setValue(QString("outOfRangeDataStrategy"), outOfRangeDataStrategyToString(_inputDevice->_outOfRangeDataStrategy));
}
}
settings.endGroup();
@ -446,6 +471,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
hmdDesktopTracking = iter.value().toBool();
} else if (iter.key() == "desktopMode") {
hmdDesktopMode = iter.value().toBool();
} else if (iter.key() == "outOfRangeDataStrategy") {
_outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(iter.value().toString());
}
iter++;
}
@ -468,6 +495,7 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM;
configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM;
configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy);
return configurationSettings;
}
@ -484,6 +512,10 @@ void ViveControllerManager::InputDevice::emitCalibrationStatus() {
emit inputConfiguration->calibrationStatus(status);
}
static controller::Pose buildPose(const glm::mat4& mat, const glm::vec3& linearVelocity, const glm::vec3& angularVelocity) {
return controller::Pose(extractTranslation(mat), glmExtractRotation(mat), linearVelocity, angularVelocity);
}
void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) {
uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex;
printDeviceTrackingResultChange(deviceIndex);
@ -492,35 +524,48 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde
_nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid &&
poseIndex <= controller::TRACKED_OBJECT_15) {
mat4& mat = mat4();
vec3 linearVelocity = vec3();
vec3 angularVelocity = vec3();
// check if the device is tracking out of range, then process the correct pose depending on the result.
if (_nextSimPoseData.vrPoses[deviceIndex].eTrackingResult != vr::TrackingResult_Running_OutOfRange) {
mat = _nextSimPoseData.poses[deviceIndex];
linearVelocity = _nextSimPoseData.linearVelocities[deviceIndex];
angularVelocity = _nextSimPoseData.angularVelocities[deviceIndex];
} else {
mat = _lastSimPoseData.poses[deviceIndex];
linearVelocity = _lastSimPoseData.linearVelocities[deviceIndex];
angularVelocity = _lastSimPoseData.angularVelocities[deviceIndex];
// make sure that we do not overwrite the pose in the _lastSimPose with incorrect data.
_nextSimPoseData.poses[deviceIndex] = _lastSimPoseData.poses[deviceIndex];
_nextSimPoseData.linearVelocities[deviceIndex] = _lastSimPoseData.linearVelocities[deviceIndex];
_nextSimPoseData.angularVelocities[deviceIndex] = _lastSimPoseData.angularVelocities[deviceIndex];
controller::Pose pose;
switch (_outOfRangeDataStrategy) {
case OutOfRangeDataStrategy::Drop:
default:
// Drop - Mark all non Running_OK results as invald
if (_nextSimPoseData.vrPoses[deviceIndex].eTrackingResult == vr::TrackingResult_Running_OK) {
pose = buildPose(_nextSimPoseData.poses[deviceIndex], _nextSimPoseData.linearVelocities[deviceIndex], _nextSimPoseData.angularVelocities[deviceIndex]);
} else {
pose.valid = false;
}
break;
case OutOfRangeDataStrategy::None:
// None - Ignore eTrackingResult all together
pose = buildPose(_nextSimPoseData.poses[deviceIndex], _nextSimPoseData.linearVelocities[deviceIndex], _nextSimPoseData.angularVelocities[deviceIndex]);
break;
case OutOfRangeDataStrategy::Freeze:
// Freeze - Dont invalide non Running_OK poses, instead just return the last good pose.
if (_nextSimPoseData.vrPoses[deviceIndex].eTrackingResult == vr::TrackingResult_Running_OK) {
pose = buildPose(_nextSimPoseData.poses[deviceIndex], _nextSimPoseData.linearVelocities[deviceIndex], _nextSimPoseData.angularVelocities[deviceIndex]);
} else {
pose = buildPose(_lastSimPoseData.poses[deviceIndex], _lastSimPoseData.linearVelocities[deviceIndex], _lastSimPoseData.angularVelocities[deviceIndex]);
// make sure that we do not overwrite the pose in the _lastSimPose with incorrect data.
_nextSimPoseData.poses[deviceIndex] = _lastSimPoseData.poses[deviceIndex];
_nextSimPoseData.linearVelocities[deviceIndex] = _lastSimPoseData.linearVelocities[deviceIndex];
_nextSimPoseData.angularVelocities[deviceIndex] = _lastSimPoseData.angularVelocities[deviceIndex];
}
break;
}
controller::Pose pose(extractTranslation(mat), glmExtractRotation(mat), linearVelocity, angularVelocity);
if (pose.valid) {
// transform into avatar frame
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
_poseStateMap[poseIndex] = pose.transform(controllerToAvatar);
// transform into avatar frame
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
_poseStateMap[poseIndex] = pose.transform(controllerToAvatar);
// but _validTrackedObjects remain in sensor frame
_validTrackedObjects.push_back(std::make_pair(poseIndex, pose));
_trackedControllers++;
// but _validTrackedObjects remain in sensor frame
_validTrackedObjects.push_back(std::make_pair(poseIndex, pose));
_trackedControllers++;
} else {
// insert invalid pose into state map
_poseStateMap[poseIndex] = pose;
}
} else {
controller::Pose invalidPose;
_poseStateMap[poseIndex] = invalidPose;

View file

@ -60,11 +60,18 @@ public:
virtual void saveSettings() const override;
virtual void loadSettings() override;
enum class OutOfRangeDataStrategy {
None,
Freeze,
Drop
};
private:
class InputDevice : public controller::InputDevice {
public:
InputDevice(vr::IVRSystem*& system);
bool isHeadControllerMounted() const { return _overrideHead; }
private:
// Device functions
controller::Input::NamedVector getAvailableInputs() const override;
@ -162,6 +169,7 @@ private:
FilteredStick _filteredLeftStick;
FilteredStick _filteredRightStick;
std::string _headsetName {""};
OutOfRangeDataStrategy _outOfRangeDataStrategy { OutOfRangeDataStrategy::None };
std::vector<PuckPosePair> _validTrackedObjects;
std::map<uint32_t, glm::mat4> _pucksPostOffset;