Alex Vakulenko | 4f079d0 | 2017-01-27 14:41:25 -0800 | [diff] [blame^] | 1 | // 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 | |
| 14 | using android::dvr::vec3; |
| 15 | using android::dvr::quat; |
| 16 | |
| 17 | namespace { |
| 18 | |
| 19 | // Prints usage information to stderr. |
| 20 | void 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. |
| 40 | void 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. |
| 51 | bool 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. |
| 123 | bool 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. |
| 160 | bool 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. |
| 181 | enum 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. |
| 190 | constexpr Action kDefaultAction = Action::Query; |
| 191 | |
| 192 | } // namespace |
| 193 | |
| 194 | int 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 | } |