34 #include <boost/assert.hpp>
40 #include <FPExceptionEnabler.h>
52 static const auto LINEAR_VELOCITY_CUTOFF = 0.2;
53 static const auto ANGULAR_VELOCITY_CUTOFF = 1.e-4;
56 static const std::size_t REQUIRED_SAMPLES = 10;
61 static const auto NEAR_MESSAGE_CUTOFF = 0.3;
64 : m_params(params), m_roomCalib(
Eigen::Isometry3d::Identity()) {
65 enterCameraPoseAcquisitionState();
69 Eigen::Matrix<double, 12, 12>
const &
71 BOOST_ASSERT_MSG(running(),
72 "Only valid if fusion is in the running state!");
73 return m_runningData->getErrorCovariance();
76 void VideoIMUFusion::enterRunningState(
80 FPExceptionEnabler fpe;
83 std::cout <<
"\nVideo-IMU fusion: Camera pose acquired, entering normal "
85 std::cout <<
"Camera is located in the room at roughly "
86 << m_rTc.translation().transpose() << std::endl;
88 if (m_params.cameraIsForward) {
90 Eigen::AngleAxisd correction(-yaw, Eigen::Vector3d::UnitY());
91 m_roomCalib = Eigen::Isometry3d(correction);
94 m_state = State::Running;
96 m_params, m_rTc, orientation, report.
pose, timestamp));
99 m_startupData.reset();
100 ei::map(m_camera) = m_roomCalib * m_rTc;
105 if (m_state != State::Running) {
109 Eigen::Vector3d::UnitY() * m_params.eyeHeight;
110 m_lastTime = timestamp;
113 m_runningData->handleIMUReport(timestamp, report);
116 updateFusedOutput(timestamp);
119 const Eigen::Vector3d &angVel) {
121 static const auto DT = 1. / 50.;
124 ei::map(m_lastVelocity.angularVelocity.incrementalRotation) =
125 osvr::util::quat_exp_map((angVel * DT).eval()).exp();
126 m_lastVelocity.angularVelocity.dt = DT;
128 ei::map(m_lastVelocity.linearVelocity) = Eigen::Vector3d::Zero();
130 m_lastVelTime = timestamp;
132 if (m_state != State::Running) {
136 m_runningData->handleIMUVelocity(timestamp, angVel);
138 updateFusedOutput(timestamp);
141 void VideoIMUFusion::updateFusedOutput(
const OSVR_TimeValue ×tamp) {
142 Eigen::Isometry3d initialPose =
143 Eigen::Translation3d(m_runningData->getPosition() +
144 Eigen::Vector3d::UnitY() * m_params.eyeHeight) *
145 m_runningData->getOrientation();
146 Eigen::Isometry3d transformed = m_roomCalib * initialPose;
147 ei::map(m_lastPose).
rotation() = Eigen::Quaterniond(transformed.rotation());
149 Eigen::Vector3d(transformed.translation());
150 m_lastTime = timestamp;
156 "handleVideoTrackerDataWhileRunning() called when not running!");
158 m_runningData->handleVideoTrackerReport(timestamp, report);
160 updateFusedOutput(timestamp);
163 Eigen::Isometry3d videoPose =
164 m_roomCalib * m_runningData->takeCameraPoseToRoom(report.
pose);
165 ei::map(m_reorientedVideo) = videoPose;
171 : last(
getNow()), positionFilter(filters::one_euro::Params{}),
172 orientationFilter(filters::one_euro::Params{}) {}
173 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
177 auto dt =
duration(timestamp, last);
187 Eigen::Isometry3d rTc = Eigen::Isometry3d(ei::map(orientation).quat()) *
189 positionFilter.filter(dt, rTc.translation());
190 orientationFilter.filter(dt, Eigen::Quaterniond(rTc.rotation()));
191 auto linearVel = positionFilter.getDerivativeMagnitude();
192 auto angVel = orientationFilter.getDerivativeMagnitude();
194 if (linearVel < LINEAR_VELOCITY_CUTOFF &&
195 angVel < ANGULAR_VELOCITY_CUTOFF) {
199 <<
"Video-IMU fusion: Hold still, measuring camera pose";
201 std::cout <<
"." << std::flush;
207 std::cout << std::endl;
210 if (!toldToMoveCloser &&
213 <<
"\n\nNOTE: For best results, during tracker/server "
214 "startup, hold your head/HMD still closer than "
215 << NEAR_MESSAGE_CUTOFF
216 <<
" meters from the tracking camera for a few "
217 "seconds, then rotate slowly in all directions.\n\n"
219 toldToMoveCloser =
true;
220 }
else if (toldToMoveCloser && !toldDistanceIsGood &&
222 0.9 * NEAR_MESSAGE_CUTOFF) {
224 <<
"\nThat distance looks good, hold it right there.\n"
226 toldDistanceIsGood =
true;
232 std::cout <<
"\n" << std::endl;
236 bool finished()
const {
return reports >= REQUIRED_SAMPLES; }
238 Eigen::Isometry3d getRoomToCamera()
const {
239 Eigen::Isometry3d ret;
240 ret.fromPositionOrientationScale(positionFilter.getState(),
241 orientationFilter.getState(),
242 Eigen::Vector3d::Constant(1));
247 std::size_t reports = 0;
250 bool toldToMoveCloser =
false;
251 bool toldDistanceIsGood =
false;
253 filters::OneEuroFilter<Eigen::Vector3d> positionFilter;
254 filters::OneEuroFilter<Eigen::Quaterniond> orientationFilter;
257 void VideoIMUFusion::enterCameraPoseAcquisitionState() {
266 "handleVideoTrackerDataDuringStartup() called when running!");
267 m_startupData->handleReport(timestamp, report, orientation);
268 if (m_startupData->finished()) {
269 enterRunningState(m_startupData->getRoomToCamera(), timestamp, report,
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void handleReport(const OSVR_TimeValue ×tamp, const OSVR_PoseReport &report, const OSVR_OrientationState &orientation)
OSVR_PoseState pose
The pose structure, containing a position vector and a rotation quaternion.
void handleVideoTrackerDataWhileRunning(const OSVR_TimeValue ×tamp, const OSVR_PoseReport &report)
double osvrVec3GetZ(OSVR_Vec3 const *v)
Accessor for Vec3 component Z.
VideoIMUFusion(VideoIMUFusionParams const ¶ms=VideoIMUFusionParams())
Constructor.
void getNow(TimeValue &tv)
Set the given TimeValue to the current time.
OSVR_Quaternion rotation
Orientation as a unit quaternion.
auto extractYaw(T const &quat) -> decltype(std::atan(quat.w()))
Eigen::Matrix< double, 12, 12 > const & getErrorCovariance() const
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void handleIMUData(const OSVR_TimeValue ×tamp, const OSVR_OrientationReport &report)
A structure defining a quaternion, often a unit quaternion representing 3D rotation.
We do not yet know the relative pose of the camera.
double duration(TimeValue const &a, TimeValue const &b)
Get a double containing seconds between the time points.
~VideoIMUFusion()
Out-of-line destructor required for unique_ptr pimpl idiom.
Header defining some filters for Eigen datatypes.
Eigen::Map< Eigen::Vector3d > translation() const
Filters for use with Eigen datatypes.
TransformType transform() const
Read-only accessor for the pose as an Eigen transform.
void handleVideoTrackerDataDuringStartup(const OSVR_TimeValue ×tamp, const OSVR_PoseReport &report, const OSVR_OrientationState &orientation)
Report type for an orientation callback on a tracker interface.
OSVR_CBool linearVelocityValid
Whether the data source reports valid data for #OSVR_VelocityState::linearVelocity.
void handleIMUVelocity(const OSVR_TimeValue ×tamp, const Eigen::Vector3d &angVel)
Header for interoperation between the Eigen math library, the internal mini math library, and VRPN's quatlib.
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
OSVR_OrientationState rotation
The rotation unit quaternion.
OSVR_Vec3 translation
Position vector.
Report type for a pose (position and orientation) callback on a tracker interface.