blob: 2288a862823d41147c0458d56c85febb5be32914 [file] [log] [blame]
Alex Vakulenko4f079d02017-01-27 14:41:25 -08001// pose is a utility to query and manipulate the current pose via the pose
2// service.
3
4#include <cmath>
5#include <cstdio>
6#include <iomanip>
7#include <iostream>
8#include <regex>
9#include <vector>
10
11#include <private/dvr/types.h>
12#include <dvr/pose_client.h>
13
14using android::dvr::vec3;
15using android::dvr::quat;
16
17namespace {
18
19// Prints usage information to stderr.
20void PrintUsage(const char* executable_name) {
21 std::cerr << "Usage: " << executable_name
22 << " [--identity|--set=...|--unfreeze]\n"
23 << "\n"
24 << " no arguments: display the current pose.\n"
25 << " --identity: freeze the pose to the identity pose.\n"
26 << " --set=rx,ry,rz,rw[,px,py,pz]: freeze the pose to the given "
27 "state. rx,ry,rz,rw are interpreted as rotation quaternion. "
28 " px, py, pz as position (0,0,0 if omitted).\n"
29 << " --mode=mode: sets mode to one of normal, head_turn:slow, "
30 "head_turn:fast, rotate:slow, rotate:medium, rotate:fast, "
31 "circle_strafe.\n"
32 << " --unfreeze: sets the mode to normal.\n"
33 << " --log_controller=[true|false]: starts and stops controller"
34 " logs\n"
35 << std::endl;
36}
37
38// If return_code is negative, print out its corresponding string description
39// and exit the program with a non-zero exit code.
40void ExitIfNegative(int return_code) {
41 if (return_code < 0) {
42 std::cerr << "Error: " << strerror(-return_code) << std::endl;
43 std::exit(1);
44 }
45}
46
47// Parses the following command line flags:
48// --identity
49// --set=rx,ry,rz,rw[,px,py,pz]
50// Returns false if parsing fails.
51bool ParseState(const std::string& arg, DvrPoseState* out_state) {
52 if (arg == "--identity") {
53 *out_state = {.head_from_start_rotation = {0.f, 0.f, 0.f, 1.f},
54 .head_from_start_translation = {0.f, 0.f, 0.f},
55 .timestamp_ns = 0,
56 .sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f}};
57 return true;
58 }
59
60 const std::string prefix("--set=");
61 if (arg.size() < 6 || arg.compare(0, prefix.size(), prefix) != 0) {
62 return false;
63 }
64
65 // Tokenize by ','.
66 std::regex split_by_comma("[,]+");
67 std::sregex_token_iterator token_it(arg.begin() + prefix.size(), arg.end(),
68 split_by_comma,
69 -1 /* return inbetween parts */);
70 std::sregex_token_iterator token_end;
71
72 // Convert to float and store values.
73 std::vector<float> values;
74 for (; token_it != token_end; ++token_it) {
75 std::string token = *(token_it);
76 float value = 0.f;
77 if (sscanf(token.c_str(), "%f", &value) != 1) {
78 std::cerr << "Unable to parse --set value as float: " << token
79 << std::endl;
80 return false;
81 } else {
82 values.push_back(value);
83 }
84 }
85
86 if (values.size() != 4 && values.size() != 7) {
87 std::cerr << "Unable to parse --set, expected either 4 or 7 of values."
88 << std::endl;
89 return false;
90 }
91
92 float norm2 = values[0] * values[0] + values[1] * values[1] +
93 values[2] * values[2] + values[3] * values[3];
94 if (std::abs(norm2 - 1.f) > 1e-4) {
95 if (norm2 < 1e-8) {
96 std::cerr << "--set quaternion norm close to zero." << std::endl;
97 return false;
98 }
99 float norm = std::sqrt(norm2);
100 values[0] /= norm;
101 values[1] /= norm;
102 values[2] /= norm;
103 values[3] /= norm;
104 }
105
106 out_state->head_from_start_rotation = {values[0], values[1], values[2],
107 values[3]};
108
109 if (values.size() == 7) {
110 out_state->head_from_start_translation = {values[4], values[5], values[6]};
111 } else {
112 out_state->head_from_start_translation = {0.f, 0.f, 0.f};
113 }
114
115 out_state->timestamp_ns = 0;
116 out_state->sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f};
117
118 return true;
119}
120
121// Parses the command line flag --mode.
122// Returns false if parsing fails.
123bool ParseSetMode(const std::string& arg, DvrPoseMode* mode) {
124 const std::string prefix("--mode=");
125 if (arg.size() < prefix.size() ||
126 arg.compare(0, prefix.size(), prefix) != 0) {
127 return false;
128 }
129
130 std::string value = arg.substr(prefix.size());
131
132 if (value == "normal") {
133 *mode = DVR_POSE_MODE_6DOF;
134 return true;
135 } else if (value == "head_turn:slow") {
136 *mode = DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW;
137 return true;
138 } else if (value == "head_turn:fast") {
139 *mode = DVR_POSE_MODE_MOCK_HEAD_TURN_FAST;
140 return true;
141 } else if (value == "rotate:slow") {
142 *mode = DVR_POSE_MODE_MOCK_ROTATE_SLOW;
143 return true;
144 } else if (value == "rotate:medium") {
145 *mode = DVR_POSE_MODE_MOCK_ROTATE_MEDIUM;
146 return true;
147 } else if (value == "rotate:fast") {
148 *mode = DVR_POSE_MODE_MOCK_ROTATE_FAST;
149 return true;
150 } else if (value == "circle_strafe") {
151 *mode = DVR_POSE_MODE_MOCK_CIRCLE_STRAFE;
152 return true;
153 } else {
154 return false;
155 }
156}
157
158// Parses the command line flag --controller_log.
159// Returns false if parsing fails.
160bool ParseLogController(const std::string& arg, bool* log_enabled) {
161 const std::string prefix("--log_controller=");
162 if (arg.size() < prefix.size() ||
163 arg.compare(0, prefix.size(), prefix) != 0) {
164 return false;
165 }
166
167 std::string value = arg.substr(prefix.size());
168
169 if (value == "false") {
170 *log_enabled = false;
171 return true;
172 } else if (value == "true") {
173 *log_enabled = true;
174 return true;
175 } else {
176 return false;
177 }
178}
179
180// The different actions that the tool can perform.
181enum class Action {
182 Query, // Query the current pose.
183 Set, // Set the pose and freeze.
184 Unfreeze, // Set the pose mode to normal.
185 SetMode, // Sets the pose mode.
186 LogController, // Start/stop controller logging in sensord.
187};
188
189// The action to perform when no arguments are passed to the tool.
190constexpr Action kDefaultAction = Action::Query;
191
192} // namespace
193
194int main(int argc, char** argv) {
195 Action action = kDefaultAction;
196 DvrPoseState state;
197 DvrPoseMode pose_mode = DVR_POSE_MODE_6DOF;
198 bool log_controller = false;
199
200 // Parse command-line arguments.
201 for (int i = 1; i < argc; ++i) {
202 const std::string arg = argv[i];
203 if (ParseState(arg, &state) && action == kDefaultAction) {
204 action = Action::Set;
205 } else if (arg == "--unfreeze" && action == kDefaultAction) {
206 action = Action::Unfreeze;
207 } else if (ParseSetMode(arg, &pose_mode) && action == kDefaultAction) {
208 action = Action::SetMode;
209 } else if (ParseLogController(arg, &log_controller)) {
210 action = Action::LogController;
211 } else {
212 PrintUsage(argv[0]);
213 return 1;
214 }
215 }
216
217 auto pose_client = dvrPoseCreate();
218 if (!pose_client) {
219 std::cerr << "Unable to create pose client." << std::endl;
220 return 1;
221 }
222
223 switch (action) {
224 case Action::Query: {
225 ExitIfNegative(dvrPosePoll(pose_client, &state));
226 uint64_t timestamp = state.timestamp_ns;
227 const auto& rotation = state.head_from_start_rotation;
228 const auto& translation = state.head_from_start_translation;
229 const auto& rotation_velocity = state.sensor_from_start_rotation_velocity;
230 quat q(rotation.w, rotation.x, rotation.y, rotation.z);
231 vec3 angles = q.matrix().eulerAngles(0, 1, 2);
232 angles = angles * 180.f / M_PI;
233 vec3 x = q * vec3(1.0f, 0.0f, 0.0f);
234 vec3 y = q * vec3(0.0f, 1.0f, 0.0f);
235 vec3 z = q * vec3(0.0f, 0.0f, 1.0f);
236
237 std::cout << "timestamp_ns: " << timestamp << std::endl
238 << "rotation_quaternion: " << rotation.x << ", " << rotation.y
239 << ", " << rotation.z << ", " << rotation.w << std::endl
240 << "rotation_angles: " << angles.x() << ", " << angles.y()
241 << ", " << angles.z() << std::endl
242 << "translation: " << translation.x << ", " << translation.y
243 << ", " << translation.z << std::endl
244 << "rotation_velocity: " << rotation_velocity.x << ", "
245 << rotation_velocity.y << ", " << rotation_velocity.z
246 << std::endl
247 << "axes: " << std::setprecision(3)
248 << "x(" << x.x() << ", " << x.y() << ", " << x.z() << "), "
249 << "y(" << y.x() << ", " << y.y() << ", " << y.z() << "), "
250 << "z(" << z.x() << ", " << z.y() << ", " << z.z() << "), "
251 << std::endl;
252 break;
253 }
254 case Action::Set: {
255 ExitIfNegative(dvrPoseFreeze(pose_client, &state));
256 break;
257 }
258 case Action::Unfreeze: {
259 ExitIfNegative(dvrPoseSetMode(pose_client, DVR_POSE_MODE_6DOF));
260 break;
261 }
262 case Action::SetMode: {
263 ExitIfNegative(dvrPoseSetMode(pose_client, pose_mode));
264 break;
265 }
266 case Action::LogController: {
267 ExitIfNegative(
268 dvrPoseLogController(pose_client, log_controller));
269 break;
270 }
271 }
272
273 dvrPoseDestroy(pose_client);
274}