Compare commits

...
8 Commits
3 changed files with 101 additions and 43 deletions

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Justin Li
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+53 -34
View File
@@ -104,6 +104,22 @@ struct DSample
Eigen::Vector3d ref, target;
};
bool StartsWith(const std::string &str, const std::string &prefix)
{
if (str.length() < prefix.length())
return false;
return str.compare(0, prefix.length(), prefix) == 0;
}
bool EndsWith(const std::string &str, const std::string &suffix)
{
if (str.length() < suffix.length())
return false;
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}
Eigen::Vector3d AxisFromRotationMatrix3(Eigen::Matrix3d rot)
{
return Eigen::Vector3d(rot(2,1) - rot(1,2), rot(0,2) - rot(2,0), rot(1,0) - rot(0,1));
@@ -136,22 +152,6 @@ DSample DeltaRotationSamples(Sample s1, Sample s2)
return ds;
}
bool StartsWith(const std::string &str, const std::string &prefix)
{
if (str.length() < prefix.length())
return false;
return str.compare(0, prefix.length(), prefix) == 0;
}
bool EndsWith(const std::string &str, const std::string &suffix)
{
if (str.length() < suffix.length())
return false;
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}
Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
{
std::vector<DSample> deltas;
@@ -165,7 +165,7 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
deltas.push_back(delta);
}
}
printf("\ngot %zd samples with %zd delta samples\n", samples.size(), deltas.size());
printf("got %zd samples with %zd delta samples\n", samples.size(), deltas.size());
// Kabsch algorithm
@@ -205,7 +205,6 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
rot.transposeInPlace();
Eigen::Vector3d euler = rot.eulerAngles(2, 1, 0) * 180.0 / EIGEN_PI;
euler[2] *= -1;
printf("rotation yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[2], euler[0]);
return euler;
@@ -246,10 +245,9 @@ Eigen::Vector3d CalibrateTranslation(const std::vector<Sample> &samples)
}
Eigen::Vector3d trans = coefficients.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(constants);
trans(0) *= -1.0;
auto transcm = trans * 100.0;
printf("\ntranslation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
printf("translation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
return transcm;
}
@@ -259,7 +257,7 @@ Sample CollectSample(const CalibrationContext &ctx)
reference.bPoseIsValid = false;
target.bPoseIsValid = false;
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
reference = devicePoses[ctx.referenceID];
target = devicePoses[ctx.targetID];
@@ -281,7 +279,7 @@ bool PickDevices(CalibrationContext &ctx)
char buffer[vr::k_unMaxPropertyStringSize];
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
{
@@ -405,30 +403,50 @@ void ScanAndApplyProfile(const CalibrationContext &ctx)
{
char buffer[vr::k_unMaxPropertyStringSize];
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
{
auto deviceClass = vr::VRSystem()->GetTrackedDeviceClass(id);
if (deviceClass == vr::TrackedDeviceClass_Invalid)
continue;
/*if (deviceClass == vr::TrackedDeviceClass_HMD) // for debugging unexpected universe switches
{
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
auto universeId = vr::VRSystem()->GetUint64TrackedDeviceProperty(id, vr::Prop_CurrentUniverseId_Uint64, &err);
printf("uid %d err %d\n", universeId, err);
continue;
}*/
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
if (err == vr::TrackedProp_Success)
if (err != vr::TrackedProp_Success)
continue;
std::string trackingSystem(buffer);
if (trackingSystem != ctx.calibratedTrackingSystem)
continue;
if (deviceClass == vr::TrackedDeviceClass_TrackingReference)
{
std::string trackingSystem(buffer);
// TODO(pushrax): detect zero reference switches and adjust calibration automatically
//auto p = devicePoses[id].mDeviceToAbsoluteTracking.m;
//printf("%d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
}
else
{
//printf("setting calibration for %d (%s)\n", id, buffer);
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
InputEmulator.setWorldFromDriverRotationOffset(id, vrRotQuat);
if (trackingSystem == ctx.calibratedTrackingSystem)
{
//printf("setting calibration for %d (%s)\n", id, buffer);
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
InputEmulator.setWorldFromDriverRotationOffset(id, vrRotQuat);
auto vrTransVec = VRTranslationVec(ctx.calibratedTranslation);
InputEmulator.setWorldFromDriverTranslationOffset(id, vrTransVec);
auto vrTransVec = VRTranslationVec(ctx.calibratedTranslation);
InputEmulator.setWorldFromDriverTranslationOffset(id, vrTransVec);
InputEmulator.enableDeviceOffsets(id, true);
}
InputEmulator.enableDeviceOffsets(id, true);
}
}
}
@@ -498,6 +516,7 @@ void CalibrationTick()
if (samples.size() == totalSamples)
{
printf("\n");
if (ctx.state == Rotation)
{
ctx.calibratedRotation = CalibrateRotation(samples);
+27 -9
View File
@@ -2,14 +2,17 @@
Use VR devices from one company with any other.
This is **beta software** and may not work for you. A quick video demo is available at https://www.youtube.com/watch?v=Khzta0hgvrA
This is **beta software** and may not work for you. A quick video walkthrough of the calibration process is available at https://www.youtube.com/watch?v=W3TnQd9JMl4
## Usage
### Calibration
If you don't already run a setup with multiple device types, see [Setting up SteamVR](#setting-up-steamvr).
0. Install [OpenVR-InputEmulator](https://github.com/matzman666/OpenVR-InputEmulator).
1. Download and unzip the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases) of OpenVR-SpaceCalibrator.
2. Run SteamVR, and turn on your Touch controllers and only one Vive device to use for calibration.
* Make sure your SteamVR and Oculus room setups are correct. If a lighthouse or sensor has moved since your last room setup, the calibration won't be calculated properly.
3. Run OpenVR-SpaceCalibrator.
4. Hold the left Touch controller and your Vive device in your left hand securely, like they're glued together.
5. Click "Start Calibration"
@@ -18,17 +21,32 @@ This is **beta software** and may not work for you. A quick video demo is availa
Next time you run SteamVR and OpenVR-InputEmulator it will load the calibration automatically and apply it to any Vive devices you turn on.
## Manually editing the calibration
### Setting up SteamVR
Every hardware designer with their own tracking system needs to make a "driver"
so SteamVR can see their tracking data. SteamVR by default will load only one driver at a time,
but we can tell it to load all of them by editing the vrsettings config file.
Open `Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings` in a text editor,
look for the line that has `"activateMultipleDrivers": false` and change the `false` to `true`.
In some guides online you may also see references to `requireHmd`, this does _not_ need to be changed
unless you truly want to be able to run without any kind of HMD.
Sometimes when SteamVR updates this file seems to get wiped, if your setup stops working you might
have to edit the config again.
### Manually editing the calibration
If you'd like to make a manual change to the calibration, the values are in `openvr_space_calibration.txt` in the same folder as the exe.
The first 4 numbers are the rotation (yaw, pitch, roll) in degrees, and the next 3 numbers are the translation (x, y, z) in centimeters.
The first 3 numbers are the rotation (yaw, pitch, roll) in degrees, and the next 3 numbers are the translation (x, y, z) in centimeters.
### Compiling your own build
1. Install boost 1.63 to `lib/boost_1_63_0` (required for IPC to OpenVR-InputEmulator). https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/
2. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
## The math
See [math.pdf](https://github.com/pushrax/OpenVR-SpaceCalibrator/blob/master/math.pdf) for details.
If you have some ideas for how to improve the calibration process, let me know!
## Compiling your own build
1. Install boost 1.63 to `lib/boost_1_63_0` (required for IPC to OpenVR-InputEmulator). https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/
2. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.