Program Listing for File alphanumeric_viewer.cpp

Return to documentation for file (/tmp/ws/src/aerostack2/as2_user_interfaces/as2_alphanumeric_viewer/src/alphanumeric_viewer.cpp)

// Copyright 2024 Universidad Politécnica de Madrid
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the Universidad Politécnica de Madrid nor the names of its
//      contributors may be used to endorse or promote products derived from
//      this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/*!*******************************************************************************************
 *  \file       alphanumeric_viewer.cpp
 *  \brief      Alphanumeric viewer source file.
 *  \authors    Javier Melero Deza
 *  \copyright  Copyright (c) 2024 Universidad Politécnica de Madrid
 *              All Rights Reserved
 ********************************************************************************/

#include "alphanumeric_viewer.hpp"

AlphanumericViewer::AlphanumericViewer()
: as2::Node("alphanumeric_viewer") {}

void AlphanumericViewer::run()
{
  command = getch();
  switch (command) {
    case 'M':
    case 'm':  // Navigation
      erase();
      refresh();
      printSummaryMenu();
      window = 0;
      break;
    case 'S':
    case 's':  // Sensor
      erase();
      refresh();
      printSensorMenu();
      window = 1;
      break;
    case 'N':
    case 'n':  // Navigation
      erase();
      refresh();
      printNavigationMenu();
      window = 2;
      break;
    case 'P':
    case 'p':  // Navigation
      erase();
      refresh();
      printPlatformMenu();
      window = 3;
      break;
  }

  if (command == '\033') {
    getch();
    switch (getch()) {  // the real value
      case 'D':
        // code for arrow left
        if (window == 0) {
          break;
        }
        window--;
        break;
      case 'C':
        // code for arrow right
        if (window == 3) {
          break;
        }
        window++;
        break;
    }
    switch (window) {
      case 0:
        erase();
        refresh();
        printSummaryMenu();
        break;
      case 1:
        erase();
        refresh();
        printSensorMenu();
        break;
      case 2:
        erase();
        refresh();
        printNavigationMenu();
        break;
      case 3:
        erase();
        refresh();
        printPlatformMenu();
        break;
    }
  }

  // Print values
  switch (window) {
    case 0:
      printSummaryValues();
      break;
    case 1:
      printSensorValues();
      break;
    case 2:
      printNavigationValues();
      break;
    case 3:
      printPlatformValues();
      break;
  }
  // erase();
  // Refresh
  refresh();
}

void AlphanumericViewer::setupNode()
{
  interface_printout_stream << std::fixed << std::setprecision(2) << std::setfill('0');

  self_localization_pose_sub_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
    this->generate_global_name(as2_names::topics::self_localization::pose),
    as2_names::topics::sensor_measurements::qos,
    std::bind(&AlphanumericViewer::poseCallback, this, std::placeholders::_1));

  self_localization_speed_sub_ = this->create_subscription<geometry_msgs::msg::TwistStamped>(
    this->generate_global_name(as2_names::topics::self_localization::twist),
    as2_names::topics::self_localization::qos,
    std::bind(&AlphanumericViewer::twistCallback, this, std::placeholders::_1));

  battery_sub_ = this->create_subscription<sensor_msgs::msg::BatteryState>(
    this->generate_global_name(as2_names::topics::sensor_measurements::battery),
    as2_names::topics::sensor_measurements::qos,
    std::bind(&AlphanumericViewer::batteryCallback, this, std::placeholders::_1));

  imu_sub_ = this->create_subscription<sensor_msgs::msg::Imu>(
    this->generate_global_name(as2_names::topics::sensor_measurements::imu),
    as2_names::topics::sensor_measurements::qos,
    std::bind(&AlphanumericViewer::imuCallback, this, std::placeholders::_1));

  status_sub_ = this->create_subscription<as2_msgs::msg::PlatformInfo>(
    this->generate_global_name(as2_names::topics::platform::info),
    as2_names::topics::platform::qos,
    std::bind(&AlphanumericViewer::platformCallback, this, std::placeholders::_1));

  actuator_command_pose_sub_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
    this->generate_global_name(as2_names::topics::actuator_command::pose),
    as2_names::topics::actuator_command::qos,
    std::bind(&AlphanumericViewer::actuatorPoseCallback, this, std::placeholders::_1));

  actuator_command_thrust_sub_ = this->create_subscription<as2_msgs::msg::Thrust>(
    this->generate_global_name(as2_names::topics::actuator_command::thrust),
    as2_names::topics::actuator_command::qos,
    std::bind(&AlphanumericViewer::actuatorThrustCallback, this, std::placeholders::_1));

  actuator_command_twist_sub_ = this->create_subscription<geometry_msgs::msg::TwistStamped>(
    this->generate_global_name(as2_names::topics::actuator_command::twist),
    as2_names::topics::actuator_command::qos,
    std::bind(&AlphanumericViewer::actuatorSpeedCallback, this, std::placeholders::_1));

  controller_info_sub_ = this->create_subscription<as2_msgs::msg::ControllerInfo>(
    this->generate_global_name(as2_names::topics::controller::info),
    as2_names::topics::controller::qos_info,
    std::bind(&AlphanumericViewer::controllerCallback, this, std::placeholders::_1));

  position_reference_sub_ = this->create_subscription<geometry_msgs::msg::PoseStamped>(
    this->generate_global_name(as2_names::topics::motion_reference::pose),
    as2_names::topics::motion_reference::qos,
    std::bind(&AlphanumericViewer::poseReferenceCallback, this, std::placeholders::_1));

  speed_reference_sub_ = this->create_subscription<geometry_msgs::msg::TwistStamped>(
    this->generate_global_name(as2_names::topics::motion_reference::twist),
    as2_names::topics::motion_reference::qos,
    std::bind(&AlphanumericViewer::speedReferenceCallback, this, std::placeholders::_1));

  /*trajectory_reference_sub_ =
     this->create_subscription<as2_msgs::msg::TrajectoryWaypoints::SharedPtr>(
      this->generate_global_name(as2_names::topics::motion_reference::trajectory),
      as2_names::topics::motion_reference::traj_gen_qos,
      std::bind(&AlphanumericViewer::trajectoryReferenceCallback, this, std::placeholders::_1));*/

  gps_sub_ = this->create_subscription<sensor_msgs::msg::NavSatFix>(
    this->generate_global_name(as2_names::topics::sensor_measurements::gps),
    as2_names::topics::sensor_measurements::qos,
    std::bind(&AlphanumericViewer::gpsCallback, this, std::placeholders::_1));
}

void AlphanumericViewer::poseCallback(const geometry_msgs::msg::PoseStamped::SharedPtr _msg)
{
  self_localization_pose_ = *_msg;
  current_pose_aux = true;
}
void AlphanumericViewer::twistCallback(const geometry_msgs::msg::TwistStamped::SharedPtr _msg)
{
  self_localization_twist_ = *_msg;
  current_speed_aux = true;
}
void AlphanumericViewer::batteryCallback(const sensor_msgs::msg::BatteryState::SharedPtr _msg)
{
  battery_status_ = *_msg;
  if (battery_status_.percentage > 1.0) {
    battery_mode_ = 1;
  }
  battery_aux = true;
}
void AlphanumericViewer::imuCallback(const sensor_msgs::msg::Imu::SharedPtr _msg)
{
  imu_ = *_msg;
  imu_aux = true;
}
void AlphanumericViewer::platformCallback(const as2_msgs::msg::PlatformInfo::SharedPtr _msg)
{
  platform_info_ = *_msg;
  platform_info_aux = true;
}
void AlphanumericViewer::actuatorPoseCallback(
  const geometry_msgs::msg::PoseStamped::SharedPtr _msg)
{
  actuator_pose_ = *_msg;
  actuator_command_pose_aux = true;
}
void AlphanumericViewer::actuatorThrustCallback(const as2_msgs::msg::Thrust::SharedPtr _msg)
{
  actuator_thrust_ = *_msg;
  actuator_command_thrust_aux = true;
}
void AlphanumericViewer::actuatorSpeedCallback(
  const geometry_msgs::msg::TwistStamped::SharedPtr _msg)
{
  actuator_twist_ = *_msg;
  actuator_command_twist_aux = true;
}
void AlphanumericViewer::controllerCallback(const as2_msgs::msg::ControllerInfo::SharedPtr _msg)
{
  controller_info_ = *_msg;
  controller_info_aux = true;
}
void AlphanumericViewer::poseReferenceCallback(
  const geometry_msgs::msg::PoseStamped::SharedPtr _msg)
{
  reference_pose_ = *_msg;
  current_pose_reference_aux = true;
}
void AlphanumericViewer::speedReferenceCallback(
  const geometry_msgs::msg::TwistStamped::SharedPtr _msg)
{
  reference_twist_ = *_msg;
  current_speed_reference_aux = true;
}
/*void AlphanumericViewer::trajectoryReferenceCallback (const
as2_msgs::msg::TrajectoryWaypoints::SharedPtr _msg){ reference_traj_ = *_msg;
  current_trajectory_reference_aux = true;
}*/
void AlphanumericViewer::gpsCallback(const sensor_msgs::msg::NavSatFix::SharedPtr _msg)
{
  gps_ = *_msg;
  gps_aux = true;
}

void AlphanumericViewer::printSummaryMenu()
{
  clearValues();

  move(0, 0);
  printw("                - ALPHANUMERIC VIEWER OF AERIAL ROBOTICS DATA -");
  move(1, 0);
  printw("          Key: M (Summary), S (sensors), N (navigation), P (platform)");
  move(2, 0);
  printw("               ^                                                     ");
  // Left column
  move(3, 0);
  printw(" Drone id:");
  move(4, 0);
  printw(" Battery charge:");
  move(6, 0);
  printw(" IMU MEASUREMENTS");
  move(7, 0);
  printw(" Orientation IMU (ypr):");
  move(8, 0);
  printw(" Angular speed IMU (ypr):");
  move(9, 0);
  printw(" Acceleration IMU (xyz):");
  move(11, 0);
  printw(" LOCALIZATION");
  move(12, 0);
  printw(" Position (xyz):");
  move(13, 0);
  printw(" Linear Speed (xyz):");
  move(14, 0);
  printw(" Orientation (ypr):");
  move(15, 0);
  printw(" Angular Speed (ypr):");
  // right column
  move(6, 58);
  printw(" PLATFORM STATUS");
  move(8, 58);
  printw(" Conected:");
  move(9, 58);
  printw(" Armed:");
  move(10, 58);
  printw(" Offboard:");
  move(12, 58);
  printw(" Status:");
  // Bottom layout
  move(17, 0);
  printw(" CONTROLLER CONTROL MODE");
  move(18, 0);
  printw(" Yaw Mode:");
  move(19, 0);
  printw(" Control Mode:");
  move(20, 0);
  printw(" Frame Mode:");
  move(17, 41);
  printw(" PLATFORM CONTROL MODE");
  move(18, 41);
  printw(" Yaw Mode:");
  move(19, 41);
  printw(" Control Mode:");
  move(20, 41);
  printw(" Frame Mode:");
}

void AlphanumericViewer::printNavigationMenu()
{
  clearValues();

  move(0, 0);
  printw("                - ALPHANUMERIC VIEWER OF AERIAL ROBOTICS DATA -");
  move(1, 0);
  printw("          Key: M (Summary), S (sensors), N (navigation), P (platform)");
  move(2, 0);
  printw("                                         ^                           ");
  // Measurements
  move(4, 0);
  printw(" MEASUREMENTS");
  move(5, 0);
  printw(" Altitude(z):");
  move(6, 0);
  printw(" Orientation IMU (ypr):");
  move(7, 0);
  printw(" Angular speed IMU (ypr):");
  move(8, 0);
  printw(" Acceleration IMU (xyz):");

  // Localization
  move(11, 0);
  printw(" LOCALIZATION");
  move(12, 0);
  printw(" Position (xyz):");
  move(13, 0);
  printw(" Linear Speed (xyz):");
  move(14, 0);
  printw(" Orientation (ypr):");
  move(15, 0);
  printw(" Angular Speed (ypr):");
  // move(16,0);
  // printw(" Status:");
}

void AlphanumericViewer::printSensorMenu()
{
  clearValues();

  move(0, 0);
  printw("                - ALPHANUMERIC VIEWER OF AERIAL ROBOTICS DATA -");
  move(1, 0);
  printw("          Key: M (Summary), S (sensors), N (navigation), P (platform)");
  move(2, 0);
  printw("                            ^                                        ");
  // Left column
  move(3, 0);
  printw(" Drone id:");
  move(5, 0);
  printw(" Battery charge:");
  move(7, 0);
  printw(" Speed (x,y,z):");
  move(9, 0);
  printw(" Orientation IMU (yaw,pitch,roll):");
  move(11, 0);
  printw(" Angular Speed IMU (yaw,pitch,roll):");
  move(13, 0);
  printw(" Acceleration IMU (x,y,z):");

  // Right column
  move(3, 50);
  printw("Altitude (-z):");
  move(5, 50);
  printw("Altitude (sea level):");
  move(7, 50);
  printw("Temperature:");
  move(9, 50);
  printw("GPS Coordinates:");
  move(10, 50);
  printw("Lat:");
  move(11, 50);
  printw("Lon:");
  move(12, 50);
  printw("Alt:");
}

void AlphanumericViewer::printPlatformMenu()
{
  clearValues();

  move(0, 0);
  printw("                - ALPHANUMERIC VIEWER OF AERIAL ROBOTICS DATA -");
  move(1, 0);
  printw("          Key: M (Summary), S (sensors), N (navigation), P (platform)");
  move(2, 0);
  printw("                                                         ^           ");
  // Left column
  // Reference

  // Actuator commands
  move(4, 0);
  printw(" ACTUATOR COMMANDS");
  move(5, 0);
  printw(" Orientation (r,p,y):");
  move(6, 0);
  printw(" Linear Speed (x,y,z):");
  move(7, 0);
  printw(" Thrust:");
  move(8, 0);
  printw(" Angular Speed (r,p,y):");

  move(10, 0);
  printw(" REFERENCES");
  move(11, 0);
  printw(" Position (x,y,z):");
  move(12, 0);
  printw(" Linear Speed (x,y,z):");
  move(13, 0);
  printw(" Orientation (r,p,y):");
  move(14, 0);
  printw(" Angular Speed (r,p,y):");
  move(16, 0);
  printw(" CONTROLLER CONTROL MODE");
  move(17, 0);
  printw(" Yaw Mode:");
  move(18, 0);
  printw(" Control Mode:");
  move(19, 0);
  printw(" Frame Mode:");
  move(16, 41);
  printw(" PLATFORM CONTROL MODE");
  move(17, 41);
  printw(" Yaw Mode:");
  move(18, 41);
  printw(" Control Mode:");
  move(19, 41);
  printw(" Frame Mode:");
  move(5, 58);
  printw(" Conected:");
  move(6, 58);
  printw(" Armed:");
  move(7, 58);
  printw(" Offboard:");
  move(10, 58);
  printw(" Status:");
}

void AlphanumericViewer::printStream(float var, bool aux)
{
  if (aux) {
    interface_printout_stream.clear();
    interface_printout_stream.str(std::string());
    if (var > -0.01) {
      interface_printout_stream << std::setw(5) << std::internal << fabs(var);
      attron(COLOR_PAIR(1));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(1));
    } else {
      interface_printout_stream << std::setw(6) << std::internal << var;
      attron(COLOR_PAIR(2));
      printw("%s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(2));
    }
  } else {
    printw(" --.--");
  }
}

// Print float using stringstream with 3 units
void AlphanumericViewer::printStream3(float var, bool aux)
{
  if (aux) {
    interface_printout_stream.clear();
    interface_printout_stream.str(std::string());
    if (var > -0.01) {
      interface_printout_stream << std::setw(6) << std::internal << fabs(var);
      attron(COLOR_PAIR(1));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(1));
    } else {
      interface_printout_stream << std::setw(7) << std::internal << var;
      attron(COLOR_PAIR(2));
      printw("%s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(2));
    }
  } else {
    printw(" ---.--");
  }
}

// Print double using stringstream
void AlphanumericViewer::printStream(double var, bool aux)
{
  if (aux) {
    interface_printout_stream.clear();
    interface_printout_stream.str(std::string());
    if (var > -0.01) {
      interface_printout_stream << std::setw(5) << std::internal << fabs(var);
      attron(COLOR_PAIR(1));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(1));
    } else {
      interface_printout_stream << std::setw(6) << std::internal << var;
      attron(COLOR_PAIR(2));
      printw("%s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(2));
    }
  } else {
    printw(" --.--");
  }
}

void AlphanumericViewer::printSummaryValues()
{
  move(3, 11);
  attron(COLOR_PAIR(4));
  printw("%s", this->get_namespace());
  attroff(COLOR_PAIR(4));
  move(4, 17);
  printBattery();

  tf2::Matrix3x3 imu_m(tf2::Quaternion(
      imu_.orientation.x, imu_.orientation.y, imu_.orientation.z,
      imu_.orientation.w));
  double r = 0;
  double p = 0;
  double yaw = 0;
  imu_m.getRPY(r, p, yaw);
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  if (std::isnan(yaw)) {yaw = 0.0;}

  move(7, 26);
  printStream(yaw, imu_aux);
  printw(",");
  move(7, 33);
  printStream(p, imu_aux);
  printw(",");
  move(7, 40);
  printStream(r, imu_aux);
  printw(" rad   ");
  move(8, 26);
  printStream(imu_.angular_velocity.z, imu_aux);
  printw(",");
  move(8, 33);
  printStream(imu_.angular_velocity.y, imu_aux);
  printw(",");
  move(8, 40);
  printStream(imu_.angular_velocity.x, imu_aux);
  printw(" rad/s  ");

  // Acceleration IMU
  move(9, 26);
  printStream(imu_.linear_acceleration.x, imu_aux);
  printw(",");
  move(9, 33);
  printStream(imu_.linear_acceleration.y, imu_aux);
  printw(",");
  move(9, 40);
  printStream(imu_.linear_acceleration.z, imu_aux);
  printw(" m/s2   ");

  // Localization
  // Pose
  move(12, 26);
  printStream3(self_localization_pose_.pose.position.x, current_pose_aux);
  printw(",");
  move(12, 34);
  printStream3(self_localization_pose_.pose.position.y, current_pose_aux);
  printw(",");
  move(12, 42);
  printStream3(self_localization_pose_.pose.position.z, current_pose_aux);
  printw(" m ");
  // Speed
  move(13, 26);
  printStream(self_localization_twist_.twist.linear.x, current_speed_aux);
  printw(",");
  move(13, 33);
  printStream(self_localization_twist_.twist.linear.y, current_speed_aux);
  printw(",");
  move(13, 40);
  printStream(self_localization_twist_.twist.linear.z, current_speed_aux);
  printw(" m/s ");
  // Pose(ypr)
  tf2::Matrix3x3 pose_m(tf2::Quaternion(
      self_localization_pose_.pose.orientation.x, self_localization_pose_.pose.orientation.y,
      self_localization_pose_.pose.orientation.z, self_localization_pose_.pose.orientation.w));
  pose_m.getRPY(r, p, yaw);
  if (std::isnan(yaw)) {yaw = 0.0;}
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  move(14, 26);
  printStream(yaw, current_pose_aux);
  printw(",");
  move(14, 33);
  printStream(p, current_pose_aux);
  printw(",");
  move(14, 40);
  printStream(r, current_pose_aux);
  printw(" rad ");
  // Speed(ypr)
  move(15, 26);
  printStream(self_localization_twist_.twist.angular.z, current_speed_aux);
  printw(",");
  move(15, 33);
  printStream(self_localization_twist_.twist.angular.y, current_speed_aux);
  printw(",");
  move(15, 40);
  printStream(self_localization_twist_.twist.angular.x, current_speed_aux);
  printw(" rad/s ");
  move(18, 11);
  printControlModeInYaw();
  move(19, 15);
  printControlModeInControl();
  move(20, 13);
  printControlModeInFrame();
  move(18, 52);
  printControlModeOutYaw();
  move(19, 56);
  printControlModeOutControl();
  move(20, 54);
  printControlModeOutFrame();
  move(12, 68);
  printQuadrotorState();
  printPlatformStatus(8);
}

void AlphanumericViewer::printSensorValues()
{
  // DroneID
  move(4, 4);
  attron(COLOR_PAIR(4));
  printw("%s", this->get_namespace());
  attroff(COLOR_PAIR(4));
  // Battery
  move(6, 4);
  printBattery();
  // Speed
  move(8, 4);
  printStream(self_localization_twist_.twist.linear.x, current_speed_aux);
  printw(",");
  move(8, 11);
  printStream(self_localization_twist_.twist.linear.y, current_speed_aux);
  printw(",");
  move(8, 18);
  printStream(self_localization_twist_.twist.linear.z, current_speed_aux);
  printw(" m/s   ");

  // Pose IMU
  tf2::Matrix3x3 imu_m(tf2::Quaternion(
      imu_.orientation.x, imu_.orientation.y, imu_.orientation.z,
      imu_.orientation.w));
  double r = 0;
  double p = 0;
  double yaw = 0;
  imu_m.getRPY(r, p, yaw);
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  if (std::isnan(yaw)) {yaw = 0.0;}

  move(10, 4);
  printStream(yaw, imu_aux);
  printw(",");
  move(10, 11);
  printStream(p, imu_aux);
  printw(",");
  move(10, 18);
  printStream(r, imu_aux);
  printw(" rad   ");

  // Speed IMU
  move(12, 4);
  printStream(imu_.angular_velocity.z, imu_aux);
  printw(",");
  move(12, 11);
  printStream(imu_.angular_velocity.y, imu_aux);
  printw(",");
  move(12, 18);
  printStream(imu_.angular_velocity.x, imu_aux);
  printw(" rad/s  ");

  // Acceleration IMU
  move(14, 4);
  printStream(imu_.linear_acceleration.x, imu_aux);
  printw(",");
  move(14, 11);
  printStream(imu_.linear_acceleration.y, imu_aux);
  printw(",");
  move(14, 18);
  printStream(imu_.linear_acceleration.z, imu_aux);
  printw(" m/s2   ");

  // Altitude
  move(4, 52);
  printStream(self_localization_pose_.pose.position.z, current_pose_aux);
  printw(" m");
  // Altitude sea level
  move(6, 52);
  printStream(0.0, altitude_sea_level_aux);
  printw(" m");
  // Temperature
  move(8, 52);
  printStream(0.0, temperature_aux);
  printw(" Degrees celsius");
  interface_printout_stream << std::fixed << std::setprecision(8) << std::setfill('0');
  move(10, 54);
  printStream(gps_.latitude, gps_aux);
  move(11, 54);
  printStream(gps_.longitude, gps_aux);
  move(12, 54);
  printStream(gps_.altitude, gps_aux);
  interface_printout_stream << std::fixed << std::setprecision(2) << std::setfill('0');
}

void AlphanumericViewer::printNavigationValues()
{
  // Measurements
  move(5, 26);
  printStream(self_localization_pose_.pose.position.z, current_pose_aux);
  printw(" m");

  // Pose IMU
  tf2::Matrix3x3 imu_m(tf2::Quaternion(
      imu_.orientation.x, imu_.orientation.y, imu_.orientation.z,
      imu_.orientation.w));
  double r = 0;
  double p = 0;
  double yaw = 0;
  imu_m.getRPY(r, p, yaw);
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  if (std::isnan(yaw)) {yaw = 0.0;}

  move(6, 26);
  printStream(yaw, imu_aux);
  printw(",");
  move(6, 33);
  printStream(p, imu_aux);
  printw(",");
  move(6, 40);
  printStream(r, imu_aux);
  printw(" rad   ");

  // Speed IMU
  move(7, 26);
  printStream(imu_.angular_velocity.z, imu_aux);
  printw(",");
  move(7, 33);
  printStream(imu_.angular_velocity.y, imu_aux);
  printw(",");
  move(7, 40);
  printStream(imu_.angular_velocity.x, imu_aux);
  printw(" rad/s  ");

  // Acceleration IMU
  move(8, 26);
  printStream(imu_.linear_acceleration.x, imu_aux);
  printw(",");
  move(8, 33);
  printStream(imu_.linear_acceleration.y, imu_aux);
  printw(",");
  move(8, 40);
  printStream(imu_.linear_acceleration.z, imu_aux);
  printw(" m/s2   ");

  // Localization
  // Pose
  move(12, 26);
  printStream3(self_localization_pose_.pose.position.x, current_pose_aux);
  printw(",");
  move(12, 34);
  printStream3(self_localization_pose_.pose.position.y, current_pose_aux);
  printw(",");
  move(12, 42);
  printStream3(self_localization_pose_.pose.position.z, current_pose_aux);
  printw(" m ");
  // Speed
  move(13, 26);
  printStream(self_localization_twist_.twist.linear.x, current_speed_aux);
  printw(",");
  move(13, 33);
  printStream(self_localization_twist_.twist.linear.y, current_speed_aux);
  printw(",");
  move(13, 40);
  printStream(self_localization_twist_.twist.linear.z, current_speed_aux);
  printw(" m/s ");
  // Pose(ypr)
  tf2::Matrix3x3 pose_m(tf2::Quaternion(
      self_localization_pose_.pose.orientation.x, self_localization_pose_.pose.orientation.y,
      self_localization_pose_.pose.orientation.z, self_localization_pose_.pose.orientation.w));
  pose_m.getRPY(r, p, yaw);
  if (std::isnan(yaw)) {yaw = 0.0;}
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  move(14, 26);
  printStream(yaw, current_pose_aux);
  printw(",");
  move(14, 33);
  printStream(p, current_pose_aux);
  printw(",");
  move(14, 40);
  printStream(r, current_pose_aux);
  printw(" rad ");
  // Speed(ypr)
  move(15, 26);
  printStream(self_localization_twist_.twist.angular.z, current_speed_aux);
  printw(",");
  move(15, 33);
  printStream(self_localization_twist_.twist.angular.y, current_speed_aux);
  printw(",");
  move(15, 40);
  printStream(self_localization_twist_.twist.angular.x, current_speed_aux);
  printw(" rad/s ");
}

void AlphanumericViewer::printPlatformValues()
{
  // move(3,54);
  // printQuadrotorState();

  // Actuator commands
  if (thrust_aux) {
    move(5, 30);
    printStream(actuator_thrust_.thrust, thrust_aux);
    printw(" N ,");
    move(6, 37);
    printStream(actuator_thrust_.thrust_normalized, thrust_aux);
    printw(" normalized  ");
    // Speed(z)
    move(7, 30);
    printStream(actuator_twist_.twist.linear.z, actuator_command_twist_aux);
    printw(" m/s  ");
    // Thrust
    // Speed(yaw)
    move(8, 30);
    printStream(actuator_twist_.twist.angular.z, actuator_command_twist_aux);
    printw(" rad/s  ");
  } else {
    // Pitch roll
    tf2::Matrix3x3 actuator_m(
      tf2::Quaternion(
        actuator_pose_.pose.orientation.x, actuator_pose_.pose.orientation.y,
        actuator_pose_.pose.orientation.z, actuator_pose_.pose.orientation.w));
    double r = 0;
    double p = 0;
    double yaw = 0;
    actuator_m.getRPY(r, p, yaw);
    if (std::isnan(r)) {r = 0.0;}
    if (std::isnan(p)) {p = 0.0;}
    if (std::isnan(yaw)) {yaw = 0.0;}
    move(5, 28);
    printStream(r, current_pose_aux);
    printw(",");
    move(5, 35);
    printStream(p, current_pose_aux);
    printw(",");
    move(5, 42);
    printStream(yaw, current_pose_aux);
    printw(" rad  ");
    // Speed(z)
    move(6, 28);
    printStream(actuator_twist_.twist.linear.x, current_speed_aux);
    printw(",");
    move(6, 35);
    printStream(actuator_twist_.twist.linear.y, current_speed_aux);
    printw(",");
    move(6, 42);
    printStream(actuator_twist_.twist.linear.z, current_speed_aux);
    printw(" m/s  ");
    // Thrust
    move(7, 28);
    printStream(actuator_thrust_.thrust, thrust_aux);
    printw(" N  ");
    // Speed(yaw)
    move(8, 28);
    printStream(actuator_twist_.twist.angular.x, current_speed_aux);
    printw(",");
    move(8, 35);
    printStream(actuator_twist_.twist.angular.y, current_speed_aux);
    printw(",");
    move(8, 42);
    printStream(actuator_twist_.twist.angular.z, current_speed_aux);
    printw(" rad/s  ");
  }

  // References
  // Pose
  move(11, 28);
  printStream3(reference_pose_.pose.position.x, current_pose_reference_aux);
  printw(",");
  move(11, 36);
  printStream3(reference_pose_.pose.position.y, current_pose_reference_aux);
  printw(",");
  move(11, 44);
  printStream3(reference_pose_.pose.position.z, current_pose_reference_aux);
  printw(" m ");
  // Speed
  move(12, 28);
  printStream(reference_twist_.twist.linear.x, current_speed_reference_aux);
  printw(",");
  move(12, 35);
  printStream(reference_twist_.twist.linear.y, current_speed_reference_aux);
  printw(",");
  move(12, 42);
  printStream(reference_twist_.twist.linear.z, current_speed_reference_aux);
  printw(" m/s ");
  // Pose (yaw)
  tf2::Matrix3x3 pose_ref_m(
    tf2::Quaternion(
      reference_pose_.pose.orientation.x, reference_pose_.pose.orientation.y,
      reference_pose_.pose.orientation.z, reference_pose_.pose.orientation.w));
  double r = 0;
  double p = 0;
  double yaw = 0;
  pose_ref_m.getRPY(r, p, yaw);
  if (std::isnan(r)) {r = 0.0;}
  if (std::isnan(p)) {p = 0.0;}
  if (std::isnan(yaw)) {yaw = 0.0;}
  move(13, 28);
  printStream(r, current_pose_reference_aux);
  printw(",");
  move(13, 35);
  printStream(p, current_pose_reference_aux);
  printw(",");
  move(13, 42);
  printStream(yaw, current_pose_reference_aux);
  printw(" rad");
  // Speed (yaw)
  move(14, 28);
  printStream(reference_twist_.twist.angular.x, current_speed_reference_aux);
  printw(",");
  move(14, 35);
  printStream(reference_twist_.twist.angular.y, current_speed_reference_aux);
  printw(",");
  move(14, 42);
  printStream(reference_twist_.twist.angular.z, current_speed_reference_aux);
  printw(" rad/s  ");
  // Control mode
  move(17, 11);
  printControlModeInYaw();
  move(18, 15);
  printControlModeInControl();
  move(19, 13);
  printControlModeInFrame();
  move(17, 52);
  printControlModeOutYaw();
  move(18, 56);
  printControlModeOutControl();
  move(19, 54);
  printControlModeOutFrame();
  printPlatformStatus(5);
  move(10, 68);
  printQuadrotorState();
}

void AlphanumericViewer::printBattery()
{
  if (battery_aux) {
    interface_printout_stream << std::fixed << std::setprecision(0) << std::setfill(' ');
    interface_printout_stream.clear();
    interface_printout_stream.str(std::string());
    clrtoeol();
    refresh();
    float percentage = battery_status_.percentage;
    if (battery_mode_ == 0) {
      percentage = percentage * 100;
    }
    interface_printout_stream << std::setw(2) << std::internal << percentage;
    if (percentage == 100) {
      attron(COLOR_PAIR(1));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(1));
    }
    if (percentage > 50 && percentage < 100) {
      attron(COLOR_PAIR(1));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(1));
    }
    if (percentage <= 50 && percentage > 20) {
      attron(COLOR_PAIR(3));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(3));
    }
    if (percentage <= 20) {
      attron(COLOR_PAIR(2));
      printw(" %s", interface_printout_stream.str().c_str());
      attroff(COLOR_PAIR(2));
    }
  } else {  // Battery has not been received
    printw("---");
  }
  printw(" %%");
  interface_printout_stream << std::fixed << std::setprecision(2) << std::setfill('0');
}

void AlphanumericViewer::printPlatformStatus(int line)
{
  move(line, 70);
  if (platform_info_.connected) {
    printw("True ");
  } else {
    printw("False");
  }
  move(line + 1, 70);
  if (platform_info_.armed) {
    printw("True ");
  } else {
    printw("False");
  }
  move(line + 2, 70);
  if (platform_info_.offboard) {
    printw("True ");
  } else {
    printw("False");
  }
}

void AlphanumericViewer::printQuadrotorState()
{
  switch (platform_info_.status.state) {
    case as2_msgs::msg::PlatformStatus::LANDED:
      printw("LANDED    ");
      break;
    case as2_msgs::msg::PlatformStatus::FLYING:
      printw("FLYING    ");
      break;
    case as2_msgs::msg::PlatformStatus::EMERGENCY:
      printw("EMERGENCY ");
      break;
    case as2_msgs::msg::PlatformStatus::DISARMED:
      printw("DISARMED");
      break;
    case as2_msgs::msg::PlatformStatus::TAKING_OFF:
      printw("TAKING OFF");
      break;
    case as2_msgs::msg::PlatformStatus::LANDING:
      printw("LANDING   ");
      break;
  }
}
void AlphanumericViewer::printControlModeInYaw()
{
  switch (controller_info_.input_control_mode.yaw_mode) {
    case as2_msgs::msg::ControlMode::NONE:
      printw("NONE        ");
      break;
    case as2_msgs::msg::ControlMode::YAW_ANGLE:
      printw("YAW_ANGLE   ");
      break;
    case as2_msgs::msg::ControlMode::YAW_SPEED:
      printw("YAW_SPEED   ");
      break;
    default:
      printw("UNKNOWN     ");
      break;
  }
}

void AlphanumericViewer::printControlModeInControl()
{
  switch (controller_info_.input_control_mode.control_mode) {
    case as2_msgs::msg::ControlMode::UNSET:
      printw("UNSET        ");
      break;
    case as2_msgs::msg::ControlMode::HOVER:
      printw("HOVER        ");
      break;
    case as2_msgs::msg::ControlMode::POSITION:
      printw("POSITION     ");
      break;
    case as2_msgs::msg::ControlMode::SPEED:
      printw("SPEED        ");
      break;
    case as2_msgs::msg::ControlMode::SPEED_IN_A_PLANE:
      printw("SPEEDINAPLANE");
      break;
    case as2_msgs::msg::ControlMode::ATTITUDE:
      printw("ATTITUDE     ");
      break;
    case as2_msgs::msg::ControlMode::ACRO:
      printw("ACRO         ");
      break;
    case as2_msgs::msg::ControlMode::TRAJECTORY:
      printw("TRAJECTORY   ");
      break;
    case as2_msgs::msg::ControlMode::ACEL:
      printw("ACEL         ");
      break;
    default:
      printw("UNKNOWN      ");
      break;
  }
}

void AlphanumericViewer::printControlModeInFrame()
{
  switch (controller_info_.input_control_mode.reference_frame) {
    case as2_msgs::msg::ControlMode::UNDEFINED_FRAME:
      printw("UNDEFINED_FRAME     ");
      break;
    case as2_msgs::msg::ControlMode::LOCAL_ENU_FRAME:
      printw("LOCAL_ENU_FRAME     ");
      break;
    case as2_msgs::msg::ControlMode::BODY_FLU_FRAME:
      printw("BODY_FLU_FRAME      ");
      break;
    case as2_msgs::msg::ControlMode::GLOBAL_LAT_LONG_ASML:
      printw("GLOBAL_LAT_LONG_ASML");
      break;
    default:
      printw("UNKNOWN      ");
      break;
  }
}

void AlphanumericViewer::printControlModeOutYaw()
{
  switch (platform_info_.current_control_mode.yaw_mode) {
    case as2_msgs::msg::ControlMode::NONE:
      printw("NONE        ");
      break;
    case as2_msgs::msg::ControlMode::YAW_ANGLE:
      printw("YAW_ANGLE    ");
      break;
    case as2_msgs::msg::ControlMode::YAW_SPEED:
      printw("YAW_SPEED     ");
      break;
    default:
      printw("UNKNOWN      ");
      break;
  }
}

void AlphanumericViewer::printControlModeOutControl()
{
  switch (platform_info_.current_control_mode.control_mode) {
    case as2_msgs::msg::ControlMode::UNSET:
      printw("UNSET        ");
      break;
    case as2_msgs::msg::ControlMode::HOVER:
      printw("HOVER        ");
      break;
    case as2_msgs::msg::ControlMode::POSITION:
      printw("POSITION     ");
      break;
    case as2_msgs::msg::ControlMode::SPEED:
      printw("SPEED        ");
      break;
    case as2_msgs::msg::ControlMode::SPEED_IN_A_PLANE:
      printw("SPEEDINAPLANE");
      break;
    case as2_msgs::msg::ControlMode::ATTITUDE:
      printw("ATTITUDE     ");
      break;
    case as2_msgs::msg::ControlMode::ACRO:
      printw("ACRO         ");
      break;
    case as2_msgs::msg::ControlMode::TRAJECTORY:
      printw("TRAJECTORY   ");
      break;
    case as2_msgs::msg::ControlMode::ACEL:
      printw("ACEL         ");
      break;
    default:
      printw("UNKNOWN      ");
      break;
  }
}

void AlphanumericViewer::printControlModeOutFrame()
{
  switch (platform_info_.current_control_mode.reference_frame) {
    case as2_msgs::msg::ControlMode::UNDEFINED_FRAME:
      printw("UNDEFINED_FRAME     ");
      break;
    case as2_msgs::msg::ControlMode::LOCAL_ENU_FRAME:
      printw("LOCAL_ENU_FRAME     ");
      break;
    case as2_msgs::msg::ControlMode::BODY_FLU_FRAME:
      printw("BODY_FLU_FRAME      ");
      break;
    case as2_msgs::msg::ControlMode::GLOBAL_LAT_LONG_ASML:
      printw("GLOBAL_LAT_LONG_ASML");
      break;
    default:
      printw("UNKNOWN      ");
      break;
  }
}

void AlphanumericViewer::clearValues()
{
  gps_aux = false;
  imu_aux = false;
  thrust_aux = false;
  battery_aux = false;
  altitude_aux = false;
  temperature_aux = false;
  current_pose_aux = false;
  ground_speed_aux = false;
  current_speed_aux = false;
  platform_info_aux = false;
  controller_info_aux = false;
  altitude_sea_level_aux = false;
  actuator_command_pose_aux = false;
  current_pose_reference_aux = false;
  actuator_command_twist_aux = false;
  current_speed_reference_aux = false;
  actuator_command_thrust_aux = false;
  current_trajectory_reference_aux = false;
}

using CallbackReturn = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn;

CallbackReturn AlphanumericViewer::on_configure(const rclcpp_lifecycle::State & _state)
{
  // Set subscriptions, publishers, services, actions, etc. here.
  setupNode();
  initscr();
  start_color();
  use_default_colors();
  curs_set(0);
  noecho();
  nodelay(stdscr, TRUE);
  erase();
  refresh();
  init_pair(1, COLOR_GREEN, -1);
  init_pair(2, COLOR_RED, -1);
  init_pair(3, COLOR_YELLOW, -1);
  init_pair(4, COLOR_CYAN, -1);

  printSummaryMenu();
  return CallbackReturn::SUCCESS;
}

CallbackReturn AlphanumericViewer::on_deactivate(const rclcpp_lifecycle::State & _state)
{
  // Clean up subscriptions, publishers, services, actions, etc. here.
  return CallbackReturn::SUCCESS;
}

CallbackReturn AlphanumericViewer::on_shutdown(const rclcpp_lifecycle::State & _state)
{
  // Clean other resources here.
  endwin();
  return CallbackReturn::SUCCESS;
}