blob: 2288a862823d41147c0458d56c85febb5be32914 [file] [log] [blame]
// pose is a utility to query and manipulate the current pose via the pose
// service.
#include <cmath>
#include <cstdio>
#include <iomanip>
#include <iostream>
#include <regex>
#include <vector>
#include <private/dvr/types.h>
#include <dvr/pose_client.h>
using android::dvr::vec3;
using android::dvr::quat;
namespace {
// Prints usage information to stderr.
void PrintUsage(const char* executable_name) {
std::cerr << "Usage: " << executable_name
<< " [--identity|--set=...|--unfreeze]\n"
<< "\n"
<< " no arguments: display the current pose.\n"
<< " --identity: freeze the pose to the identity pose.\n"
<< " --set=rx,ry,rz,rw[,px,py,pz]: freeze the pose to the given "
"state. rx,ry,rz,rw are interpreted as rotation quaternion. "
" px, py, pz as position (0,0,0 if omitted).\n"
<< " --mode=mode: sets mode to one of normal, head_turn:slow, "
"head_turn:fast, rotate:slow, rotate:medium, rotate:fast, "
"circle_strafe.\n"
<< " --unfreeze: sets the mode to normal.\n"
<< " --log_controller=[true|false]: starts and stops controller"
" logs\n"
<< std::endl;
}
// If return_code is negative, print out its corresponding string description
// and exit the program with a non-zero exit code.
void ExitIfNegative(int return_code) {
if (return_code < 0) {
std::cerr << "Error: " << strerror(-return_code) << std::endl;
std::exit(1);
}
}
// Parses the following command line flags:
// --identity
// --set=rx,ry,rz,rw[,px,py,pz]
// Returns false if parsing fails.
bool ParseState(const std::string& arg, DvrPoseState* out_state) {
if (arg == "--identity") {
*out_state = {.head_from_start_rotation = {0.f, 0.f, 0.f, 1.f},
.head_from_start_translation = {0.f, 0.f, 0.f},
.timestamp_ns = 0,
.sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f}};
return true;
}
const std::string prefix("--set=");
if (arg.size() < 6 || arg.compare(0, prefix.size(), prefix) != 0) {
return false;
}
// Tokenize by ','.
std::regex split_by_comma("[,]+");
std::sregex_token_iterator token_it(arg.begin() + prefix.size(), arg.end(),
split_by_comma,
-1 /* return inbetween parts */);
std::sregex_token_iterator token_end;
// Convert to float and store values.
std::vector<float> values;
for (; token_it != token_end; ++token_it) {
std::string token = *(token_it);
float value = 0.f;
if (sscanf(token.c_str(), "%f", &value) != 1) {
std::cerr << "Unable to parse --set value as float: " << token
<< std::endl;
return false;
} else {
values.push_back(value);
}
}
if (values.size() != 4 && values.size() != 7) {
std::cerr << "Unable to parse --set, expected either 4 or 7 of values."
<< std::endl;
return false;
}
float norm2 = values[0] * values[0] + values[1] * values[1] +
values[2] * values[2] + values[3] * values[3];
if (std::abs(norm2 - 1.f) > 1e-4) {
if (norm2 < 1e-8) {
std::cerr << "--set quaternion norm close to zero." << std::endl;
return false;
}
float norm = std::sqrt(norm2);
values[0] /= norm;
values[1] /= norm;
values[2] /= norm;
values[3] /= norm;
}
out_state->head_from_start_rotation = {values[0], values[1], values[2],
values[3]};
if (values.size() == 7) {
out_state->head_from_start_translation = {values[4], values[5], values[6]};
} else {
out_state->head_from_start_translation = {0.f, 0.f, 0.f};
}
out_state->timestamp_ns = 0;
out_state->sensor_from_start_rotation_velocity = {0.f, 0.f, 0.f};
return true;
}
// Parses the command line flag --mode.
// Returns false if parsing fails.
bool ParseSetMode(const std::string& arg, DvrPoseMode* mode) {
const std::string prefix("--mode=");
if (arg.size() < prefix.size() ||
arg.compare(0, prefix.size(), prefix) != 0) {
return false;
}
std::string value = arg.substr(prefix.size());
if (value == "normal") {
*mode = DVR_POSE_MODE_6DOF;
return true;
} else if (value == "head_turn:slow") {
*mode = DVR_POSE_MODE_MOCK_HEAD_TURN_SLOW;
return true;
} else if (value == "head_turn:fast") {
*mode = DVR_POSE_MODE_MOCK_HEAD_TURN_FAST;
return true;
} else if (value == "rotate:slow") {
*mode = DVR_POSE_MODE_MOCK_ROTATE_SLOW;
return true;
} else if (value == "rotate:medium") {
*mode = DVR_POSE_MODE_MOCK_ROTATE_MEDIUM;
return true;
} else if (value == "rotate:fast") {
*mode = DVR_POSE_MODE_MOCK_ROTATE_FAST;
return true;
} else if (value == "circle_strafe") {
*mode = DVR_POSE_MODE_MOCK_CIRCLE_STRAFE;
return true;
} else {
return false;
}
}
// Parses the command line flag --controller_log.
// Returns false if parsing fails.
bool ParseLogController(const std::string& arg, bool* log_enabled) {
const std::string prefix("--log_controller=");
if (arg.size() < prefix.size() ||
arg.compare(0, prefix.size(), prefix) != 0) {
return false;
}
std::string value = arg.substr(prefix.size());
if (value == "false") {
*log_enabled = false;
return true;
} else if (value == "true") {
*log_enabled = true;
return true;
} else {
return false;
}
}
// The different actions that the tool can perform.
enum class Action {
Query, // Query the current pose.
Set, // Set the pose and freeze.
Unfreeze, // Set the pose mode to normal.
SetMode, // Sets the pose mode.
LogController, // Start/stop controller logging in sensord.
};
// The action to perform when no arguments are passed to the tool.
constexpr Action kDefaultAction = Action::Query;
} // namespace
int main(int argc, char** argv) {
Action action = kDefaultAction;
DvrPoseState state;
DvrPoseMode pose_mode = DVR_POSE_MODE_6DOF;
bool log_controller = false;
// Parse command-line arguments.
for (int i = 1; i < argc; ++i) {
const std::string arg = argv[i];
if (ParseState(arg, &state) && action == kDefaultAction) {
action = Action::Set;
} else if (arg == "--unfreeze" && action == kDefaultAction) {
action = Action::Unfreeze;
} else if (ParseSetMode(arg, &pose_mode) && action == kDefaultAction) {
action = Action::SetMode;
} else if (ParseLogController(arg, &log_controller)) {
action = Action::LogController;
} else {
PrintUsage(argv[0]);
return 1;
}
}
auto pose_client = dvrPoseCreate();
if (!pose_client) {
std::cerr << "Unable to create pose client." << std::endl;
return 1;
}
switch (action) {
case Action::Query: {
ExitIfNegative(dvrPosePoll(pose_client, &state));
uint64_t timestamp = state.timestamp_ns;
const auto& rotation = state.head_from_start_rotation;
const auto& translation = state.head_from_start_translation;
const auto& rotation_velocity = state.sensor_from_start_rotation_velocity;
quat q(rotation.w, rotation.x, rotation.y, rotation.z);
vec3 angles = q.matrix().eulerAngles(0, 1, 2);
angles = angles * 180.f / M_PI;
vec3 x = q * vec3(1.0f, 0.0f, 0.0f);
vec3 y = q * vec3(0.0f, 1.0f, 0.0f);
vec3 z = q * vec3(0.0f, 0.0f, 1.0f);
std::cout << "timestamp_ns: " << timestamp << std::endl
<< "rotation_quaternion: " << rotation.x << ", " << rotation.y
<< ", " << rotation.z << ", " << rotation.w << std::endl
<< "rotation_angles: " << angles.x() << ", " << angles.y()
<< ", " << angles.z() << std::endl
<< "translation: " << translation.x << ", " << translation.y
<< ", " << translation.z << std::endl
<< "rotation_velocity: " << rotation_velocity.x << ", "
<< rotation_velocity.y << ", " << rotation_velocity.z
<< std::endl
<< "axes: " << std::setprecision(3)
<< "x(" << x.x() << ", " << x.y() << ", " << x.z() << "), "
<< "y(" << y.x() << ", " << y.y() << ", " << y.z() << "), "
<< "z(" << z.x() << ", " << z.y() << ", " << z.z() << "), "
<< std::endl;
break;
}
case Action::Set: {
ExitIfNegative(dvrPoseFreeze(pose_client, &state));
break;
}
case Action::Unfreeze: {
ExitIfNegative(dvrPoseSetMode(pose_client, DVR_POSE_MODE_6DOF));
break;
}
case Action::SetMode: {
ExitIfNegative(dvrPoseSetMode(pose_client, pose_mode));
break;
}
case Action::LogController: {
ExitIfNegative(
dvrPoseLogController(pose_client, log_controller));
break;
}
}
dvrPoseDestroy(pose_client);
}