OSVR Reset Yaw
来源:互联网 发布:sap数据导入 编辑:程序博客网 时间:2024/05/21 10:31
作用:
该工具可用来对/me/head坐标系进行短期(在osvr server运行期间)校准,将头部的方向校正为正前方。它主要是为只有orientation数据的追踪器准备的;而带有完整pose信息的追踪器就不需要这个工具了,它们一般都会带有外部固定的已知位置的地标或者摄像头,而由于已知位置就能够建立一个不变的期望的坐标系。
如何使用:
在运行OSVR reset yaw之前,OSVR server应该先运行并且能正常接受到追踪数据。应用程序也在运行。
1.开启Reset Yaw应用程序。它会连接上OSVR Server并随后在提醒继续操作之前会获取追踪数据
2.应用程序会提示“将你的设备放置在零点方位并按下enter键”:这时头显应该朝向想要的成为正前方的方位,随后按下enter键
3.该应用程序会记录按下enter键这一刻的方位信息,然后再计算这个方位和一个默认方位间关于Y轴的相对旋转信息,随后给OSVR server发生一条信息以更新它的节点/me/head,该节点路径包含一个变形转换层可对头部坐标系进行转换操作,因此可使新的方位变为/me/head的有效正前方。
4.当所有的计算以及服务通信都完成时,应用程序会提醒再次按下enter键退出reset yaw程序,改变将会立即生效。
若是不满意,可再次运行该程序;新创建的校正数据将会刷掉旧的校正数据,所有正在运行的OSVR应用程序将会立即刷新以显示新校正数据的转换结果。
缺陷:
1.该校正数据只在当前服务进程操作时会被保存,其他任何地方都无法保存,因此当关闭OSVR server时,它们就会丢失。(大多数IMU设备在这一点上设计成在每个阶段都需要这这样的校正操作,这样才是合理的操作模式)
2.该操作只对/me/head生效,而对那些即使在同一坐标系中的追踪器或摄像头都不会起到效果。(这也是为什么说它最适合在仅仅有方位追踪器的系统中使用的原因)
3.正如名字所提示的,它只能校准偏航角yaw/heading:地平面假设正确。如果追踪被混合进它的转换中而不仅仅只是去校正它的yaw角,使用该工具也会出现错误。
代码分析:
{ namespace po = boost::program_options; // clang-format off po::options_description desc("Options"); desc.add_options() ("help", "produce help message") ("path", po::value<std::string>()->default_value("/me/head"), "path to reset-yaw on") ("no-wait", "headless mode - immediately resets yaw without waiting") ; // clang-format on po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); po::notify(vm); const bool noWait = vm.count("no-wait"); { /// Deal with command line errors or requests for help bool usage = false; if (vm.count("help")) { cout << "Usage: osvr_reset_yaw [options]" << endl; cout << desc << "\n"; return 1; } } osvr::clientkit::ClientContext ctx("com.osvr.bundled.resetyaw"); std::string const path = vm["path"].as<std::string>(); // Get the interface associated with the destination route we // are looking for. osvr::clientkit::Interface iface = ctx.getInterface(path); { ClientMainloopThread client(ctx); cout << "Running client mainloop briefly to start up..." << endl; client.loopForDuration(boost::chrono::seconds(2)); cout << "Removing any previous yaw-reset transforms..." << endl; // Get the alias element corresponding to the desired path, if possible. auto elt = getAliasElement(ctx, path); if (!elt) { // No luck, sorry. cerr << "Couldn't get the alias at " << path << endl; return -1; } // Get a reference to the source associated with the portion // of the tree that has this destination. Then clean out // any prior instance of our meddling by checking for an // entry that has our flag key in it. Then replace the // original source tree with the cleaned tree. Send this // cleaned alias back to the server. osvr::common::ParsedAlias origAlias{elt->getSource()}; if (!origAlias.isValid()) { cerr << "Couldn't parse the alias!" << endl; return -1; } cout << "Original transform: " << origAlias.getAliasValue().toStyledString() << "\n" << endl; osvr::common::GeneralizedTransform xforms{origAlias.getAliasValue()}; osvr::common::remove_if(xforms, [](Json::Value const ¤t) { return current.isMember(FLAG_KEY) && current[FLAG_KEY].isBool() && current[FLAG_KEY].asBool(); }); cout << "Cleaned transform: " << xforms.get(origAlias.getLeaf()).toStyledString() << "\n" << endl; elt->setSource( osvr::common::jsonToCompactString(xforms.get(origAlias.getLeaf()))); ctx.get()->sendRoute(createJSONAlias(path, *elt)); cout << "Sent cleaned transform, starting again and waiting a few " "seconds for startup..." << endl; client.start(); boost::this_thread::sleep(SETTLE_TIME); if (!noWait) { cout << "\n\nPlease place your device for " << path << " in its 'zero' orientation and press enter." << endl; std::cin.ignore(); } OSVR_OrientationState state; OSVR_TimeValue timestamp; OSVR_ReturnCode ret; { /// briefly interrupt the client mainloop so we can get stuff done /// with the client state. ClientMainloopThread::lock_type lock(client.getMutex()); ret = osvrGetOrientationState(iface.get(), ×tamp, &state); if (ret != OSVR_RETURN_SUCCESS) { cerr << "Sorry, no orientation state available for this path - " "are you sure you have a device plugged in and your " "path correct?" << endl; if (!noWait) { std::cin.ignore(); } return -1; } auto q = osvr::util::eigen_interop::map(state); auto yaw = osvr::util::extractYaw(q); cout << "Correction: " << -yaw << " radians about Y" << endl; Json::Value newLayer(Json::objectValue); newLayer["postrotate"]["radians"] = -yaw; newLayer["postrotate"]["axis"] = "y"; newLayer[FLAG_KEY] = true; xforms.wrap(newLayer); cout << "New source: " << xforms.get(origAlias.getLeaf()).toStyledString() << endl; elt->setSource(osvr::common::jsonToCompactString( xforms.get(origAlias.getLeaf()))); ctx.get()->sendRoute(createJSONAlias(path, *elt)); boost::this_thread::sleep(SETTLE_TIME / 2); } boost::this_thread::sleep(SETTLE_TIME); if (!noWait) { cout << "Press enter to exit."; std::cin.ignore(); } } return 0;}
输出:
- OSVR Reset Yaw
- OSVR简介
- OSVR-Vive
- An Introduction to OSVR
- OSVR-Core编译
- OSVR接入HMD设备
- osvr::clientkit::ClientContext
- VRPN-OSVR介绍
- reset()
- Reset
- Reset
- Reset
- SteamVR-OSVR(build 342)
- Roll, Pitch & Yaw
- yaw-pitch-roll
- roll pitch yaw
- Pitch Yaw Roll
- pitch yaw roll是什么
- kaoshi(Utils读取)
- Python3.6安装MySQL
- Android 使用MediaPlayer播放音频
- 生成树协议配置与管理STP——1
- c#的委托(代理)和事件
- OSVR Reset Yaw
- kaoshi(Wangluo判断)
- C++ 11 initializer_list关键字
- 阮一峰:45岁以后的人生
- 欢迎使用CSDN-markdown编辑器
- JavaWeb: 报错信息The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
- SSO单点登录
- jquery里的val,html,text方法的区别
- 走进虚拟现实游戏行业