OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
osvr_reset_yaw.cpp
Go to the documentation of this file.
1 
12 // Copyright 2015 Sensics, Inc.
13 //
14 // Licensed under the Apache License, Version 2.0 (the "License");
15 // you may not use this file except in compliance with the License.
16 // You may obtain a copy of the License at
17 //
18 // http://www.apache.org/licenses/LICENSE-2.0
19 //
20 // Unless required by applicable law or agreed to in writing, software
21 // distributed under the License is distributed on an "AS IS" BASIS,
22 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 // See the License for the specific language governing permissions and
24 // limitations under the License.
25 
26 // Internal Includes
27 #include "ClientMainloopThread.h"
31 #include <osvr/Common/PathTree.h>
33 #include <osvr/Common/PathNode.h>
36 #include <osvr/Common/ParseAlias.h>
38 #include <osvr/Util/EigenInterop.h>
39 #include <osvr/Util/UniquePtr.h>
40 #include <osvr/Util/ExtractYaw.h>
41 
42 // Library/third-party includes
43 #include <boost/program_options.hpp>
44 #include <boost/thread/thread.hpp>
45 #include <boost/date_time/posix_time/posix_time.hpp>
46 #include <boost/variant/get.hpp>
47 #include <boost/optional.hpp>
48 #include <json/value.h>
49 #include <json/reader.h>
50 
51 // Standard includes
52 #include <iostream>
53 #include <fstream>
54 #include <exception>
55 
56 using std::cout;
57 using std::cerr;
58 using std::endl;
59 
60 inline std::string
61 createJSONAlias(std::string const &path,
65  path, osvr::common::jsonParse(elt.getSource())),
66  elt.priority())
67  .toStyledString();
68 }
69 
70 boost::optional<osvr::common::elements::AliasElement>
71 getAliasElement(osvr::clientkit::ClientContext &ctx, std::string const &path) {
72  osvr::common::PathNode const *node = nullptr;
73  try {
74  node = &(ctx.get()->getPathTree().getNodeByPath(path));
75  } catch (std::exception &e) {
76  cerr << "Could not get node at path '" << path
77  << "' - exception: " << e.what() << endl;
78  return boost::none;
79  }
80  auto elt = boost::get<osvr::common::elements::AliasElement>(&node->value());
81  if (!elt) {
82  return boost::none;
83  }
84  return *elt;
85 }
86 
87 auto SETTLE_TIME = boost::posix_time::seconds(2);
88 
90 static const char FLAG_KEY[] = "resetYaw";
91 
92 int main(int argc, char *argv[]) {
93  namespace po = boost::program_options;
94  // clang-format off
95  po::options_description desc("Options");
96  desc.add_options()
97  ("help", "produce help message")
98  ("path", po::value<std::string>()->default_value("/me/head"), "path to reset-yaw on")
99  ("no-wait", "headless mode - immediately resets yaw without waiting")
100  ;
101  // clang-format on
102 
103  po::variables_map vm;
104  po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
105  po::notify(vm);
106 
107  const bool noWait = vm.count("no-wait");
108 
109  {
111  bool usage = false;
112 
113  if (vm.count("help")) {
114  cout << "Usage: osvr_reset_yaw [options]" << endl;
115  cout << desc << "\n";
116  return 1;
117  }
118  }
119  osvr::clientkit::ClientContext ctx("com.osvr.bundled.resetyaw");
120  std::string const path = vm["path"].as<std::string>();
121 
122  // Get the interface associated with the destination route we
123  // are looking for.
124  osvr::clientkit::Interface iface = ctx.getInterface(path);
125  {
126  ClientMainloopThread client(ctx);
127 
128  cout << "Running client mainloop briefly to start up..." << endl;
129  client.loopForDuration(boost::chrono::seconds(2));
130  cout << "Removing any previous yaw-reset transforms..." << endl;
131 
132  // Get the alias element corresponding to the desired path, if possible.
133  auto elt = getAliasElement(ctx, path);
134  if (!elt) {
135  // No luck, sorry.
136  cerr << "Couldn't get the alias at " << path << endl;
137  return -1;
138  }
139 
140  // Get a reference to the source associated with the portion
141  // of the tree that has this destination. Then clean out
142  // any prior instance of our meddling by checking for an
143  // entry that has our flag key in it. Then replace the
144  // original source tree with the cleaned tree. Send this
145  // cleaned alias back to the server.
146  osvr::common::ParsedAlias origAlias{elt->getSource()};
147  if (!origAlias.isValid()) {
148  cerr << "Couldn't parse the alias!" << endl;
149  return -1;
150  }
151  cout << "Original transform: "
152  << origAlias.getAliasValue().toStyledString() << "\n" << endl;
153  osvr::common::GeneralizedTransform xforms{origAlias.getAliasValue()};
154  osvr::common::remove_if(xforms, [](Json::Value const &current) {
155  return current.isMember(FLAG_KEY) && current[FLAG_KEY].isBool() &&
156  current[FLAG_KEY].asBool();
157  });
158  cout << "Cleaned transform: "
159  << xforms.get(origAlias.getLeaf()).toStyledString() << "\n"
160  << endl;
161  elt->setSource(
162  osvr::common::jsonToCompactString(xforms.get(origAlias.getLeaf())));
163  ctx.get()->sendRoute(createJSONAlias(path, *elt));
164 
165  cout << "Sent cleaned transform, starting again and waiting a few "
166  "seconds for startup..."
167  << endl;
168  client.start();
169  boost::this_thread::sleep(SETTLE_TIME);
170 
171  if (!noWait) {
172  cout << "\n\nPlease place your device for " << path
173  << " in its 'zero' orientation and press enter." << endl;
174  std::cin.ignore();
175  }
176 
177  OSVR_OrientationState state;
178  OSVR_TimeValue timestamp;
179  OSVR_ReturnCode ret;
180  {
183  ClientMainloopThread::lock_type lock(client.getMutex());
184  ret = osvrGetOrientationState(iface.get(), &timestamp, &state);
185  if (ret != OSVR_RETURN_SUCCESS) {
186  cerr << "Sorry, no orientation state available for this path - "
187  "are you sure you have a device plugged in and your "
188  "path correct?"
189  << endl;
190  if (!noWait) {
191  std::cin.ignore();
192  }
193  return -1;
194  }
195  auto q = osvr::util::eigen_interop::map(state);
196  auto yaw = osvr::util::extractYaw(q);
197  cout << "Correction: " << -yaw << " radians about Y" << endl;
198 
199  Json::Value newLayer(Json::objectValue);
200  newLayer["postrotate"]["radians"] = -yaw;
201  newLayer["postrotate"]["axis"] = "y";
202  newLayer[FLAG_KEY] = true;
203  xforms.wrap(newLayer);
204  cout << "New source: "
205  << xforms.get(origAlias.getLeaf()).toStyledString() << endl;
206 
208  xforms.get(origAlias.getLeaf())));
209  ctx.get()->sendRoute(createJSONAlias(path, *elt));
210  boost::this_thread::sleep(SETTLE_TIME / 2);
211  }
212 
213  boost::this_thread::sleep(SETTLE_TIME);
214 
215  if (!noWait) {
216  cout << "Press enter to exit.";
217  std::cin.ignore();
218  }
219  }
220  return 0;
221 }
Header.
The element type corresponding to a path alias, with a priority level for sorting out whether automat...
Header containing wrappers for some common jsoncpp operations.
Interface handle object. Typically acquired from a ClientContext.
Client context object: Create and keep one in your application. Handles lifetime management and provi...
Definition: Context_decl.h:57
Header.
::osvr::util::TreeNode< PathElement > PathNode
The specific tree node type that contains a path element.
Definition: PathNode_fwd.h:42
void sendRoute(std::string const &route)
Sends a JSON route/transform object to the server.
AliasPriority & priority()
Get/set whether this alias was automatically set (and thus subject to being override by explicit rout...
std::string & getSource()
Get the source of data for this alias.
auto extractYaw(T const &quat) -> decltype(std::atan(quat.w()))
Definition: ExtractYaw.h:47
Header to bring unique_ptr into the osvr namespace.
A structure defining a quaternion, often a unit quaternion representing 3D rotation.
Definition: QuaternionC.h:49
Container for easy manipulation of nested transforms.
int main(int argc, char *argv[])
Interface getInterface(const std::string &path)
Get the interface associated with the given path.
Definition: Context.h:61
Header.
PathNode & getNodeByPath(std::string const &path)
Returns the node indicated by the path, which must be absolute (begin with a /). Any non-existent nod...
Definition: PathTree.cpp:47
Json::Value applyPriorityToAlias(Json::Value const &alias, AliasPriority priority)
Given a JSON object describing one or more aliases, set the priority of the alias(es).
#define OSVR_RETURN_SUCCESS
The "success" value for an OSVR_ReturnCode.
Definition: ReturnCodesC.h:45
osvr::common::PathTree const & getPathTree() const
Accessor for the path tree.
Header.
OSVR_ClientContext get()
Gets the bare OSVR_ClientContext.
Definition: Context.h:109
std::string jsonToCompactString(Json::Value const &val)
Turns the JSON value into a compact string representation.
Definition: JSONHelpers.h:53
void setSource(std::string const &source)
Sets the source of this alias.
Header for interoperation between the Eigen math library, the internal mini math library, and VRPN's quatlib.
Json::Value createJSONAlias(std::string const &path, Json::Value const &destination)
Given a path and a destination, combine them into a JSON alias description.
OSVR_ReturnCode osvrGetOrientationState(OSVR_ClientInterface iface, struct OSVR_TimeValue *timestamp, OSVR_OrientationState *state)
Get Orientation state from an interface, returning failure if none \ * exists.
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Definition: TimeValueC.h:81
Json::Value jsonParse(std::string const &str)
Parses a string as JSON, returning a null value if parsing fails.
Definition: JSONHelpers.h:42
Header.
void remove_if(GeneralizedTransform &transform, UnaryPredicate pred)
Remove levels from a generalized transform as dictated by an arbitrary predicate. ...