From f26472e3a411edbc6a008d931ea6b16218acebd7 Mon Sep 17 00:00:00 2001 From: Antonio Griego Date: Sun, 1 Oct 2017 21:00:12 -0600 Subject: [PATCH] significant improvements and streamlining to the RQT GUI interface First, a disclaimer and apology: the single massive commit is the result of having to cherry pick the many apsects of this feature from other branches that were merged or partially merged into the now-deleted development branch. That being said, there is a lot of really cool things in this feature: - Unique Rover Colors: You can check this box on the sensor display tab to have reach rover's trail on the Map Frame be uniquely colored. There are 8 unique colors, if you are using more than 8 rovers than the colors are assigned in a cycle. For example, rover 0 and rover 8 will be the same color, etc. - Global Frame: You can check this box on the sensor display tab to reposition the Map Frame trails of all rovers to be as they appear in the Gazebo world. That is, the Map Frame displays all rovers at (0,0) by default from their Odometry frame of reference. This check box corrects that by offsetting their trails by their Gazebo spawn points. Unfortunately, this is for simulated rovers only at this time. - Savable Gazebo World: You can check this box on the simulation control tab to build a simulation's Gazebo world without rovers, walls, ground texture, or a collection zone will be created. The purpose of this option is to generate tag distributions using the Uniform, Clustered, or Power Law in a way that you can save the world file from Gazebo and re-use that same distribution later using the Custom world option. It will also load much faster as well when loading a pre-built distribution. - Unbounded Round Type: In addition to Preliminary and Final, you can now select the "unbounded" round type which has no barrier walls. When selected, you can also choose the square arena size from the accompanying drop down menu. When creating target distributions using Uniform, Clustered, or Power Law, the apriltag cubes will be spread out to fill the size of the arena you chose. - Number of Cubes: When building worlds with the Uniform or Clustered distributions, you can set the total number of cubes generated in the simulation control tab. The sizes of clusters are scaled based on the total amount of cubes selected. This is useful for building worlds with smaller number of cubes for testing without having to wait for a long time for the placement of many cubes. - Simulation Length Timer: There is now an option for a 20 minute timer in the Simulation Length timer drop down box. - The Task Status tab has been removed: The information previously kept in this tab has been moved to the left hand side of the GUI screen and is accessible while in both of the other tabs. - Overall streamlining and beautification(*) of the GUI: There was a lot of unused and awkward white space that was condensed and re-allocated so that the maximum amount of useful information was available in each tab of the RQT GUI. (*) Based on the writer's biased opinion, grid based layouts are pretty. --- src/rqt_rover_gui/src/MapData.cpp | 112 +- src/rqt_rover_gui/src/MapData.h | 14 +- src/rqt_rover_gui/src/MapFrame.cpp | 1013 ++++--- src/rqt_rover_gui/src/MapFrame.h | 16 + src/rqt_rover_gui/src/rover_gui_plugin.cpp | 589 ++-- src/rqt_rover_gui/src/rover_gui_plugin.h | 7 +- src/rqt_rover_gui/src/rover_gui_plugin.ui | 3116 +++++++++++++------- 7 files changed, 3190 insertions(+), 1677 deletions(-) diff --git a/src/rqt_rover_gui/src/MapData.cpp b/src/rqt_rover_gui/src/MapData.cpp index f6a3da1e..abe08bfb 100644 --- a/src/rqt_rover_gui/src/MapData.cpp +++ b/src/rqt_rover_gui/src/MapData.cpp @@ -2,9 +2,9 @@ using namespace std; -MapData::MapData( ) +MapData::MapData() { - + display_global_offset = false; } void MapData::addToGPSRoverPath(string rover, float x, float y) @@ -18,7 +18,13 @@ void MapData::addToGPSRoverPath(string rover, float x, float y) if (y < min_gps_seen_y[rover]) min_gps_seen_y[rover] = y; update_mutex.lock(); + + float offset_x = rover_global_offsets[rover].first; + float offset_y = rover_global_offsets[rover].second; + global_offset_gps_rover_path[rover].push_back(pair(x+offset_x,y-offset_y)); + gps_rover_path[rover].push_back(pair(x,y)); + update_mutex.unlock(); } @@ -34,7 +40,13 @@ void MapData::addToEncoderRoverPath(string rover, float x, float y) if (y < min_encoder_seen_y[rover]) min_encoder_seen_y[rover] = y; update_mutex.lock(); + + float offset_x = rover_global_offsets[rover].first; + float offset_y = rover_global_offsets[rover].second; + global_offset_encoder_rover_path[rover].push_back(pair(x+offset_x,y-offset_y)); + encoder_rover_path[rover].push_back(pair(x,y)); + update_mutex.unlock(); } @@ -51,7 +63,13 @@ void MapData::addToEKFRoverPath(string rover, float x, float y) if (y < min_ekf_seen_y[rover]) min_ekf_seen_y[rover] = y; update_mutex.lock(); + + float offset_x = rover_global_offsets[rover].first; + float offset_y = rover_global_offsets[rover].second; + global_offset_ekf_rover_path[rover].push_back(pair(x+offset_x,y-offset_y)); + ekf_rover_path[rover].push_back(pair(x,y)); + update_mutex.unlock(); } @@ -79,6 +97,15 @@ void MapData::addCollectionPoint(string rover, float x, float y) } +void MapData::setGlobalOffset(bool display) +{ + display_global_offset = display; +} + +void MapData::setGlobalOffsetForRover(string rover, float x, float y) +{ + rover_global_offsets[rover] = pair(x,y); +} void MapData::clear() { @@ -87,6 +114,9 @@ void MapData::clear() ekf_rover_path.clear(); encoder_rover_path.clear(); gps_rover_path.clear(); + global_offset_ekf_rover_path.clear(); + global_offset_encoder_rover_path.clear(); + global_offset_gps_rover_path.clear(); target_locations.clear(); collection_points.clear(); @@ -100,6 +130,9 @@ void MapData::clear(string rover) ekf_rover_path[rover].clear(); encoder_rover_path[rover].clear(); gps_rover_path[rover].clear(); + global_offset_ekf_rover_path[rover].clear(); + global_offset_encoder_rover_path[rover].clear(); + global_offset_gps_rover_path[rover].clear(); target_locations[rover].clear(); collection_points[rover].clear(); @@ -114,16 +147,31 @@ void MapData::clear(string rover) std::vector< std::pair >* MapData::getEKFPath(std::string rover_name) { + if(display_global_offset) + { + return &global_offset_ekf_rover_path[rover_name]; + } + return &ekf_rover_path[rover_name]; } std::vector< std::pair >* MapData::getGPSPath(std::string rover_name) { + if(display_global_offset) + { + return &global_offset_gps_rover_path[rover_name]; + } + return &gps_rover_path[rover_name]; } std::vector< std::pair >* MapData::getEncoderPath(std::string rover_name) { + if(display_global_offset) + { + return &global_offset_encoder_rover_path[rover_name]; + } + return &encoder_rover_path[rover_name]; } @@ -140,61 +188,121 @@ std::vector< std::pair >* MapData::getCollectionPoints(std::string // These functions report the maximum and minimum map values seen. This is useful for the GUI when it is calculating the map coordinate system. float MapData::getMaxGPSX(string rover_name) { + if(display_global_offset) + { + return max_gps_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return max_gps_seen_x[rover_name]; } float MapData::getMaxGPSY(string rover_name) { + if(display_global_offset) + { + return max_gps_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return max_gps_seen_y[rover_name]; } float MapData::getMinGPSX(string rover_name) { + if(display_global_offset) + { + return min_gps_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return min_gps_seen_x[rover_name]; } float MapData::getMinGPSY(string rover_name) { + if(display_global_offset) + { + return min_gps_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return min_gps_seen_y[rover_name]; } float MapData::getMaxEKFX(string rover_name) { + if(display_global_offset) + { + return max_ekf_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return max_ekf_seen_x[rover_name]; } float MapData::getMaxEKFY(string rover_name) { + if(display_global_offset) + { + return max_ekf_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return max_ekf_seen_y[rover_name]; } float MapData::getMinEKFX(string rover_name) { + if(display_global_offset) + { + return min_ekf_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return min_ekf_seen_x[rover_name]; } float MapData::getMinEKFY(string rover_name) { + if(display_global_offset) + { + return min_ekf_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return min_ekf_seen_y[rover_name]; } float MapData::getMaxEncoderX(string rover_name) { + if(display_global_offset) + { + return max_encoder_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return max_encoder_seen_x[rover_name]; } float MapData::getMaxEncoderY(string rover_name) { + if(display_global_offset) + { + return max_encoder_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return max_encoder_seen_y[rover_name]; } float MapData::getMinEncoderX(string rover_name) { + if(display_global_offset) + { + return min_encoder_seen_x[rover_name] + rover_global_offsets[rover_name].first; + } + return min_encoder_seen_x[rover_name]; } float MapData::getMinEncoderY(string rover_name) { + if(display_global_offset) + { + return min_encoder_seen_y[rover_name] - rover_global_offsets[rover_name].second; + } + return min_encoder_seen_y[rover_name]; } diff --git a/src/rqt_rover_gui/src/MapData.h b/src/rqt_rover_gui/src/MapData.h index c35208b4..b178fa2f 100644 --- a/src/rqt_rover_gui/src/MapData.h +++ b/src/rqt_rover_gui/src/MapData.h @@ -24,6 +24,9 @@ class MapData void addTargetLocation(std::string rover, float x, float y); void addCollectionPoint(std::string rover, float x, float y); + void setGlobalOffset(bool display); + void setGlobalOffsetForRover(std::string rover, float x, float y); + void clear(); void clear(std::string rover_name); void lock(); @@ -56,8 +59,13 @@ class MapData private: std::map > > gps_rover_path; - std::map > > ekf_rover_path; - std::map > > encoder_rover_path; + std::map > > ekf_rover_path; + std::map > > encoder_rover_path; + + std::map > rover_global_offsets; + std::map > > global_offset_gps_rover_path; + std::map > > global_offset_ekf_rover_path; + std::map > > global_offset_encoder_rover_path; std::map > > collection_points; std::map > > target_locations; @@ -77,6 +85,8 @@ class MapData std::map min_ekf_seen_x; std::map min_ekf_seen_y; + bool display_global_offset; + QMutex update_mutex; // To prevent race conditions when the data is being displayed by MapFrame }; diff --git a/src/rqt_rover_gui/src/MapFrame.cpp b/src/rqt_rover_gui/src/MapFrame.cpp index 135b631b..89ee6d38 100644 --- a/src/rqt_rover_gui/src/MapFrame.cpp +++ b/src/rqt_rover_gui/src/MapFrame.cpp @@ -16,621 +16,682 @@ namespace rqt_rover_gui MapFrame::MapFrame(QWidget *parent, Qt::WindowFlags flags) : QFrame(parent) { - connect(this, SIGNAL(delayedUpdate()), this, SLOT(update()), Qt::QueuedConnection); + connect(this, SIGNAL(delayedUpdate()), this, SLOT(update()), Qt::QueuedConnection); - // Scale coordinates - frame_width = this->width(); - frame_height = this->height(); + // Scale coordinates + frame_width = this->width(); + frame_height = this->height(); - // So we can keep track of relative mouse movements to make - // panning feel natural - previous_clicked_position = QPoint(0,0); + // So we can keep track of relative mouse movements to make + // panning feel natural + previous_clicked_position = QPoint(0,0); - auto_transform = true; - scale = 10; + auto_transform = true; + scale = 10; - translate_x = 0.0f; - translate_y = 0.0f; - previous_translate_x = 0.0f; - previous_translate_y = 0.0f; + translate_x = 0.0f; + translate_y = 0.0f; + previous_translate_x = 0.0f; + previous_translate_y = 0.0f; - scale_speed = 0.1; // The amount of zoom per mouse wheel angle change - translate_speed = 1.5f; + scale_speed = 0.1; // The amount of zoom per mouse wheel angle change + translate_speed = 1.5f; - display_ekf_data = false; - display_gps_data = false; - display_encoder_data = false; + display_ekf_data = false; + display_gps_data = false; + display_encoder_data = false; + display_global_offset = false; + display_unique_rover_colors = false; - frames = 0; - popout_mapframe = NULL; - popout_window = NULL; + frames = 0; + popout_mapframe = NULL; + popout_window = NULL; - map_data = NULL; + map_data = NULL; } // This can't go in the constructor or there will be an infinite regression. // Instead call from the main UI in it's startup routine. void MapFrame::createPopoutWindow( MapData * map_data ) { - popout_window = new QMainWindow(); - popout_mapframe = new MapFrame(popout_window, 0); - popout_mapframe->setMapData(map_data); + popout_window = new QMainWindow(); + popout_mapframe = new MapFrame(popout_window, 0); + popout_mapframe->setMapData(map_data); - QGridLayout* layout = new QGridLayout(); - layout->addWidget(popout_mapframe); + QGridLayout* layout = new QGridLayout(); + layout->addWidget(popout_mapframe); - QWidget* central_widget = new QWidget(); - central_widget->setLayout(layout); + QWidget* central_widget = new QWidget(); + central_widget->setLayout(layout); - popout_window->setGeometry(QRect(10, 10, 500, 500)); - popout_window->setStyleSheet("background-color: rgb(0, 0, 0); border-color: rgb(255, 255, 255);"); - popout_window->setCentralWidget(central_widget); + popout_window->setGeometry(QRect(10, 10, 500, 500)); + popout_window->setStyleSheet("background-color: rgb(0, 0, 0); border-color: rgb(255, 255, 255);"); + popout_window->setCentralWidget(central_widget); - connect(this, SIGNAL(delayedUpdate()), popout_mapframe, SLOT(update()), Qt::QueuedConnection); + connect(this, SIGNAL(delayedUpdate()), popout_mapframe, SLOT(update()), Qt::QueuedConnection); } void MapFrame::paintEvent(QPaintEvent* event) { - // Begin drawing the map - QPainter painter(this); - painter.setPen(Qt::white); - QFont font = painter.font(); - qreal font_size = font.pointSizeF(); - QFontMetrics fm(font); - - // Track the frames per second for development purposes - QString frames_per_second; - frames_per_second = QString::number(frames / (frame_rate_timer.elapsed() / 1000.0), 'f', 0) + " FPS"; + // Begin drawing the map + QPainter painter(this); + painter.setPen(Qt::white); + QFont font = painter.font(); + qreal font_size = font.pointSizeF(); + QFontMetrics fm(font); - painter.drawText(this->width()-fm.width(frames_per_second), fm.height(), frames_per_second); + // Track the frames per second for development purposes + QString frames_per_second; + frames_per_second = QString::number(frames / (frame_rate_timer.elapsed() / 1000.0), 'f', 0) + " FPS"; - frames++; + painter.drawText(this->width()-fm.width(frames_per_second), fm.height(), frames_per_second); - if (!(frames % 100)) // time how long it takes to dispay 100 frames - { - frame_rate_timer.start(); - frames = 0; - } + frames++; - // end frames per second + if (!(frames % 100)) // time how long it takes to dispay 100 frames + { + frame_rate_timer.start(); + frames = 0; + } - // Check if any rovers have been selected for display - if ( !map_data ) - { - painter.drawText(QPoint(50,50), "No map data provided"); - return; - } + // end frames per second + // Check if any rovers have been selected for display + if ( !map_data ) + { + painter.drawText(QPoint(50,50), "No map data provided"); + return; + } - // Check if any rovers have been selected for display - if ( display_list.empty() ) - { - painter.drawText(QPoint(50,50), "No rover maps selected for display"); - return; - } - map_data->lock(); + // Check if any rovers have been selected for display + if ( display_list.empty() ) + { + painter.drawText(QPoint(50,50), "No rover maps selected for display"); + return; + } - // Colorblind friendly colors - QColor green(17, 192, 131); - QColor red(255, 65, 30); + map_data->lock(); - float max_seen_x = -std::numeric_limits::max(); // std::numeric_limits::max() is the max possible floating point value - float max_seen_y = -std::numeric_limits::max(); + // Colorblind friendly colors + QColor green(17, 192, 131); + QColor red(255, 65, 30); - float min_seen_x = std::numeric_limits::max(); - float min_seen_y = std::numeric_limits::max(); + float max_seen_x = -std::numeric_limits::max(); // std::numeric_limits::max() is the max possible floating point value + float max_seen_y = -std::numeric_limits::max(); - float max_seen_width = -std::numeric_limits::max(); - float max_seen_height = -std::numeric_limits::max(); + float min_seen_x = std::numeric_limits::max(); + float min_seen_y = std::numeric_limits::max(); - int no_data_offset = 0; // So the "no data" message is not overlayed if there are multiple rovers with no data. + float max_seen_width = -std::numeric_limits::max(); + float max_seen_height = -std::numeric_limits::max(); - // Repeat the display code for each rover selected by the user - Using C++11 range syntax - for(auto rover_to_display : display_list) { - if (map_data->getEKFPath(rover_to_display)->empty() && map_data->getEncoderPath(rover_to_display)->empty() && map_data->getGPSPath(rover_to_display)->empty() && map_data->getTargetLocations(rover_to_display)->empty() && map_data->getCollectionPoints(rover_to_display)->empty()) { - painter.drawText(QPoint(50,50+no_data_offset), QString::fromStdString(rover_to_display) + ": No data."); - no_data_offset += 10; - } + int no_data_offset = 0; // So the "no data" message is not overlayed if there are multiple rovers with no data. - // Check extended kalman filter has any values in it - else if (map_data->getEKFPath(rover_to_display)->empty()) { - painter.drawText(QPoint(50,50+no_data_offset), "Map Frame: No EKF data received."); - no_data_offset += 10; - } + // Repeat the display code for each rover selected by the user - Using C++11 range syntax + for(auto rover_to_display : display_list) { + if (map_data->getEKFPath(rover_to_display)->empty() && map_data->getEncoderPath(rover_to_display)->empty() && map_data->getGPSPath(rover_to_display)->empty() && map_data->getTargetLocations(rover_to_display)->empty() && map_data->getCollectionPoints(rover_to_display)->empty()) { + painter.drawText(QPoint(50,50+no_data_offset), QString::fromStdString(rover_to_display) + ": No data."); + no_data_offset += 10; } + // Check extended kalman filter has any values in it + else if (map_data->getEKFPath(rover_to_display)->empty()) { + painter.drawText(QPoint(50,50+no_data_offset), "Map Frame: No EKF data received."); + no_data_offset += 10; + } + } - // Calculate the map bounds if in auto transform mode. Iterate over the - // rovers and get the min and max data values scale the map to include - // these values - if (auto_transform) + // Calculate the map bounds if in auto transform mode. Iterate over the + // rovers and get the min and max data values scale the map to include + // these values + if (auto_transform) + { + for(auto rover_to_display : display_list) { - for(auto rover_to_display : display_list) - { - // Set the max and min seen values depending on which data the user - // has selected to view - - // Check each of the display data options and choose the most - // extreme value from those selected by the user - - // Always include the ekf data because that is what we are using to - // position the current position marker for the rover - - if (display_ekf_data) - { - if (min_seen_x > map_data->getMinEKFX(rover_to_display)) min_seen_x = map_data->getMinEKFX(rover_to_display); - if (min_seen_y > map_data->getMinEKFY(rover_to_display)) min_seen_y = map_data->getMinEKFY(rover_to_display); - if (max_seen_x < map_data->getMaxEKFX(rover_to_display)) max_seen_x = map_data->getMaxEKFX(rover_to_display); - if (max_seen_y < map_data->getMaxEKFY(rover_to_display)) max_seen_y = map_data->getMaxEKFY(rover_to_display); - } - - if (display_gps_data) - { - if (min_seen_x > map_data->getMinGPSX(rover_to_display)) min_seen_x = map_data->getMinGPSX(rover_to_display); - if (min_seen_y > map_data->getMinGPSY(rover_to_display)) min_seen_y = map_data->getMinGPSY(rover_to_display); - if (max_seen_x < map_data->getMaxGPSX(rover_to_display)) max_seen_x = map_data->getMaxGPSX(rover_to_display); - if (max_seen_y < map_data->getMaxGPSY(rover_to_display)) max_seen_y = map_data->getMaxGPSY(rover_to_display); - } - - if (display_encoder_data) - { - if (min_seen_x > map_data->getMinEncoderX(rover_to_display)) min_seen_x = map_data->getMinEncoderX(rover_to_display); - if (min_seen_y > map_data->getMinEncoderY(rover_to_display)) min_seen_y = map_data->getMinEncoderY(rover_to_display); - if (max_seen_x < map_data->getMaxEncoderX(rover_to_display)) max_seen_x = map_data->getMaxEncoderX(rover_to_display); - if (max_seen_y < map_data->getMaxEncoderY(rover_to_display)) max_seen_y = map_data->getMaxEncoderY(rover_to_display); - } - - // Normalize the displayed coordinates to the largest coordinates - // seen since we don't know the coordinate system. - max_seen_width = max_seen_x-min_seen_x; - max_seen_height = max_seen_y-min_seen_y; - } + // Set the max and min seen values depending on which data the user + // has selected to view + + // Check each of the display data options and choose the most + // extreme value from those selected by the user + + // Always include the ekf data because that is what we are using to + // position the current position marker for the rover + + if (display_ekf_data) + { + if (min_seen_x > map_data->getMinEKFX(rover_to_display)) min_seen_x = map_data->getMinEKFX(rover_to_display); + if (min_seen_y > map_data->getMinEKFY(rover_to_display)) min_seen_y = map_data->getMinEKFY(rover_to_display); + if (max_seen_x < map_data->getMaxEKFX(rover_to_display)) max_seen_x = map_data->getMaxEKFX(rover_to_display); + if (max_seen_y < map_data->getMaxEKFY(rover_to_display)) max_seen_y = map_data->getMaxEKFY(rover_to_display); + } + + if (display_gps_data) + { + if (min_seen_x > map_data->getMinGPSX(rover_to_display)) min_seen_x = map_data->getMinGPSX(rover_to_display); + if (min_seen_y > map_data->getMinGPSY(rover_to_display)) min_seen_y = map_data->getMinGPSY(rover_to_display); + if (max_seen_x < map_data->getMaxGPSX(rover_to_display)) max_seen_x = map_data->getMaxGPSX(rover_to_display); + if (max_seen_y < map_data->getMaxGPSY(rover_to_display)) max_seen_y = map_data->getMaxGPSY(rover_to_display); + } + + if (display_encoder_data) + { + if (min_seen_x > map_data->getMinEncoderX(rover_to_display)) min_seen_x = map_data->getMinEncoderX(rover_to_display); + if (min_seen_y > map_data->getMinEncoderY(rover_to_display)) min_seen_y = map_data->getMinEncoderY(rover_to_display); + if (max_seen_x < map_data->getMaxEncoderX(rover_to_display)) max_seen_x = map_data->getMaxEncoderX(rover_to_display); + if (max_seen_y < map_data->getMaxEncoderY(rover_to_display)) max_seen_y = map_data->getMaxEncoderY(rover_to_display); + } + + // Normalize the displayed coordinates to the largest coordinates + // seen since we don't know the coordinate system. + max_seen_width = max_seen_x-min_seen_x; + max_seen_height = max_seen_y-min_seen_y; + } + } + else + { + // Perform the manual zoom and pan transform + + max_seen_width = max_seen_width_when_manual_enabled * (scale * scale_speed); + max_seen_height = max_seen_height_when_manual_enabled * (scale * scale_speed); + + min_seen_x = (min_seen_x_when_manual_enabled + translate_x) * (scale * scale_speed); + min_seen_y = (min_seen_y_when_manual_enabled + translate_y) * (scale * scale_speed); + + // emit sendInfoLogMessage("MapFrame: paint event: manual transform: min_seen_x: " + QString::number(min_seen_x) + " min_seen_y: " + QString::number(min_seen_y)); + } + + // Maintain aspect ratio + max_seen_height > max_seen_width ? max_seen_width = max_seen_height : max_seen_height = max_seen_width; + + // Calculate the axis positions + int map_origin_x = fm.width(QString::number(-max_seen_height, 'f', 1)+"m"); + int map_origin_y = 2*fm.height(); + + int map_width = this->width()-1;// Minus 1 or will go off the edge + int map_height = this->height()-1;// + + int map_center_x = map_origin_x+((map_width-map_origin_x)/2); + int map_center_y = map_origin_y+((map_height-map_origin_y)/2); + + // The map axes do not need to be redrawn for each rover so this code is + // sandwiched between the two rover display list loops + + // Draw the scale bars + //painter.setPen(Qt::gray); + //painter.drawLine(QPoint(map_center_x, map_origin_y), QPoint(map_center_x, map_height)); + //painter.drawLine(QPoint(map_origin_x, map_center_y), QPoint(map_width, map_center_y)); + //painter.setPen(Qt::white); + + // Cross hairs at map display center + QPoint axes_origin(map_origin_x,map_origin_y); + QPoint x_axis(map_width,map_origin_y); + QPoint y_axis(map_origin_x,map_height); + painter.drawLine(axes_origin, x_axis); + painter.drawLine(axes_origin, y_axis); + painter.drawLine(QPoint(map_width, map_origin_y), QPoint(map_width, map_height)); + painter.drawLine(QPoint(map_origin_x, map_height), QPoint(map_width, map_height)); + + // Draw north arrow + QPoint northArrow_point(map_center_x, 0); + QPoint northArrow_left(map_center_x - 5, 5); + QPoint northArrow_right(map_center_x + 5, 5); + QRect northArrow_textBox(northArrow_left.x(), northArrow_left.y(), 10, 15); + painter.drawLine(northArrow_left, northArrow_right); + painter.drawLine(northArrow_left, northArrow_point); + painter.drawLine(northArrow_right, northArrow_point); + painter.drawText(northArrow_textBox, QString("N")); + + // Draw rover origin crosshairs + // painter.setPen(green); + + float initial_x = 0.0; //map_data->getEKFPath(rover_to_display).begin()->first; + float initial_y = 0.001; //map_data->getEKFPath(rover_to_display).begin()->second; + float rover_origin_x = map_origin_x+((initial_x-min_seen_x)/max_seen_width)*(map_width-map_origin_x); + float rover_origin_y = map_origin_y+((initial_y-min_seen_y)/max_seen_height)*(map_height-map_origin_y); + painter.setPen(Qt::gray); + painter.drawLine(QPoint(rover_origin_x, map_origin_y), QPoint(rover_origin_x, map_height)); + painter.drawLine(QPoint(map_origin_x, rover_origin_y), QPoint(map_width, rover_origin_y)); + painter.setPen(Qt::white); + + int n_ticks = 6; + float tick_length = 5; + QPoint x_axis_ticks[n_ticks]; + QPoint y_axis_ticks[n_ticks]; + + for (int i = 0; i < n_ticks-1; i++) + { + x_axis_ticks[i].setX(axes_origin.x()+(i+1)*map_width/n_ticks); + x_axis_ticks[i].setY(axes_origin.y()); + + y_axis_ticks[i].setX(axes_origin.x()); + y_axis_ticks[i].setY(axes_origin.y()+(i+1)*map_height/n_ticks); + } + + for (int i = 0; i < n_ticks-1; i++) + { + painter.drawLine(x_axis_ticks[i], QPoint(x_axis_ticks[i].x(), x_axis_ticks[i].y()+tick_length)); + painter.drawLine(y_axis_ticks[i], QPoint(y_axis_ticks[i].x()+tick_length, y_axis_ticks[i].y())); + } + + for (int i = 0; i < n_ticks-1; i++) + { + float fraction_of_map_to_rover_x = (rover_origin_x-map_origin_x)/map_width; + float fraction_of_map_to_rover_y = (rover_origin_y-map_origin_y)/map_height; + float x_label_f = (i+1)*max_seen_width/n_ticks-fraction_of_map_to_rover_x*max_seen_width; + float y_label_f = (i+1)*max_seen_height/n_ticks-fraction_of_map_to_rover_y*max_seen_height; + + QString x_label = QString::number(x_label_f, 'f', 1) + "m"; + QString y_label = QString::number(-y_label_f, 'f', 1) + "m"; + + int x_labels_offset_x = -(fm.width(x_label))/2; + int x_labels_offset_y = 0; + + int y_labels_offset_x = -(fm.width(y_label)); + int y_labels_offset_y = fm.height()/3; + + painter.drawText(x_axis_ticks[i].x()+x_labels_offset_x, axes_origin.y()+x_labels_offset_y, x_label); + painter.drawText(axes_origin.x()+y_labels_offset_x, y_axis_ticks[i].y()+y_labels_offset_y, y_label); + } + + // End draw scale bars + + int hardware_rover_color_index = 0; + + // Repeat the display code for each rover selected by the user - Using C++11 range syntax + for(auto rover_to_display : display_list) + { + // scale coordinates + std::vector scaled_target_locations; + for(std::vector< pair >::iterator it = map_data->getTargetLocations(rover_to_display)->begin(); it < map_data->getTargetLocations(rover_to_display)->end(); ++it) { + pair coordinate = *it; + QPoint point; + point.setX(map_origin_x+coordinate.first*map_width); + point.setY(map_origin_y+coordinate.second*map_height); + scaled_target_locations.push_back(point); } - else - { - // Perform the manual zoom and pan transform - max_seen_width = max_seen_width_when_manual_enabled * (scale * scale_speed); - max_seen_height = max_seen_height_when_manual_enabled * (scale * scale_speed); + std::vector scaled_collection_points; + for(std::vector< pair >::iterator it = map_data->getCollectionPoints(rover_to_display)->begin(); it < map_data->getCollectionPoints(rover_to_display)->end(); ++it) { + pair coordinate = *it; + QPoint point; + point.setX(map_origin_x+coordinate.first*map_width); + point.setY(map_origin_y+coordinate.second*map_height); + scaled_collection_points.push_back(point); + } - min_seen_x = (min_seen_x_when_manual_enabled + translate_x) * (scale * scale_speed); - min_seen_y = (min_seen_y_when_manual_enabled + translate_y) * (scale * scale_speed); + std::vector scaled_gps_rover_points; + for(std::vector< pair >::iterator it = map_data->getGPSPath(rover_to_display)->begin(); it < map_data->getGPSPath(rover_to_display)->end(); ++it) { + pair coordinate = *it; - // emit sendInfoLogMessage("MapFrame: paint event: manual transform: min_seen_x: " + QString::number(min_seen_x) + " min_seen_y: " + QString::number(min_seen_y)); + float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); + float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); + scaled_gps_rover_points.push_back( QPoint(x,y) ); } - // Maintain aspect ratio - max_seen_height > max_seen_width ? max_seen_width = max_seen_height : max_seen_height = max_seen_width; - - // Calculate the axis positions - int map_origin_x = fm.width(QString::number(-max_seen_height, 'f', 1)+"m"); - int map_origin_y = 2*fm.height(); - - int map_width = this->width()-1;// Minus 1 or will go off the edge - int map_height = this->height()-1;// - - int map_center_x = map_origin_x+((map_width-map_origin_x)/2); - int map_center_y = map_origin_y+((map_height-map_origin_y)/2); - - // The map axes do not need to be redrawn for each rover so this code is - // sandwiched between the two rover display list loops - - // Draw the scale bars - //painter.setPen(Qt::gray); - //painter.drawLine(QPoint(map_center_x, map_origin_y), QPoint(map_center_x, map_height)); - //painter.drawLine(QPoint(map_origin_x, map_center_y), QPoint(map_width, map_center_y)); - //painter.setPen(Qt::white); - - // Cross hairs at map display center - QPoint axes_origin(map_origin_x,map_origin_y); - QPoint x_axis(map_width,map_origin_y); - QPoint y_axis(map_origin_x,map_height); - painter.drawLine(axes_origin, x_axis); - painter.drawLine(axes_origin, y_axis); - painter.drawLine(QPoint(map_width, map_origin_y), QPoint(map_width, map_height)); - painter.drawLine(QPoint(map_origin_x, map_height), QPoint(map_width, map_height)); - - // Draw north arrow - QPoint northArrow_point(map_center_x, 0); - QPoint northArrow_left(map_center_x - 5, 5); - QPoint northArrow_right(map_center_x + 5, 5); - QRect northArrow_textBox(northArrow_left.x(), northArrow_left.y(), 10, 15); - painter.drawLine(northArrow_left, northArrow_right); - painter.drawLine(northArrow_left, northArrow_point); - painter.drawLine(northArrow_right, northArrow_point); - painter.drawText(northArrow_textBox, QString("N")); - - // Draw rover origin crosshairs - // painter.setPen(green); - - float initial_x = 0.0; //map_data->getEKFPath(rover_to_display).begin()->first; - float initial_y = 0.001; //map_data->getEKFPath(rover_to_display).begin()->second; - float rover_origin_x = map_origin_x+((initial_x-min_seen_x)/max_seen_width)*(map_width-map_origin_x); - float rover_origin_y = map_origin_y+((initial_y-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - painter.setPen(Qt::gray); - painter.drawLine(QPoint(rover_origin_x, map_origin_y), QPoint(rover_origin_x, map_height)); - painter.drawLine(QPoint(map_origin_x, rover_origin_y), QPoint(map_width, rover_origin_y)); - painter.setPen(Qt::white); + QPainterPath scaled_ekf_rover_path; + for(std::vector< pair >::iterator it = map_data->getEKFPath(rover_to_display)->begin(); it < map_data->getEKFPath(rover_to_display)->end(); ++it) { + pair coordinate = *it; + QPoint point; + float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); + float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); + + // Move to the starting point of the path without drawing a line + if (it == map_data->getEKFPath(rover_to_display)->begin()) scaled_ekf_rover_path.moveTo(x, y); + scaled_ekf_rover_path.lineTo(x, y); + } - int n_ticks = 6; - float tick_length = 5; - QPoint x_axis_ticks[n_ticks]; - QPoint y_axis_ticks[n_ticks]; + QPainterPath scaled_encoder_rover_path; + for(std::vector< pair >::iterator it = map_data->getEncoderPath(rover_to_display)->begin(); it < map_data->getEncoderPath(rover_to_display)->end(); ++it) { + + pair coordinate = *it; + QPoint point; + float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); + float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - for (int i = 0; i < n_ticks-1; i++) - { - x_axis_ticks[i].setX(axes_origin.x()+(i+1)*map_width/n_ticks); - x_axis_ticks[i].setY(axes_origin.y()); + // Move to the starting point of the path without drawing a line + if (it == map_data->getEncoderPath(rover_to_display)->begin()) scaled_encoder_rover_path.moveTo(x, y); - y_axis_ticks[i].setX(axes_origin.x()); - y_axis_ticks[i].setY(axes_origin.y()+(i+1)*map_height/n_ticks); + scaled_encoder_rover_path.lineTo(x, y); } - for (int i = 0; i < n_ticks-1; i++) + QColor rover_color = QColor(255, 255, 255); // white + + // if we have properly set a color for simulated rovers initialise the color here + // also make the popout map frame aware of the colors we use here + if(unique_simulated_rover_colors.find(rover_to_display) != unique_simulated_rover_colors.end()) { - painter.drawLine(x_axis_ticks[i], QPoint(x_axis_ticks[i].x(), x_axis_ticks[i].y()+tick_length)); - painter.drawLine(y_axis_ticks[i], QPoint(y_axis_ticks[i].x()+tick_length, y_axis_ticks[i].y())); - } + rover_color = unique_simulated_rover_colors[rover_to_display]; - for (int i = 0; i < n_ticks-1; i++) + if(popout_mapframe) + { + popout_mapframe->setUniqueRoverColor(rover_to_display, unique_simulated_rover_colors[rover_to_display]); + } + } + // caveat in the case that + // 1) we haven't set sim rover colors properly + // 2) we are using hardware rovers + else if(display_unique_rover_colors) { - float fraction_of_map_to_rover_x = (rover_origin_x-map_origin_x)/map_width; - float fraction_of_map_to_rover_y = (rover_origin_y-map_origin_y)/map_height; - float x_label_f = (i+1)*max_seen_width/n_ticks-fraction_of_map_to_rover_x*max_seen_width; - float y_label_f = (i+1)*max_seen_height/n_ticks-fraction_of_map_to_rover_y*max_seen_height; + rover_color = unique_physical_rover_colors[hardware_rover_color_index]; + } - QString x_label = QString::number(x_label_f, 'f', 1) + "m"; - QString y_label = QString::number(-y_label_f, 'f', 1) + "m"; + painter.setPen(rover_color); - int x_labels_offset_x = -(fm.width(x_label))/2; - int x_labels_offset_y = 0; + if(!display_unique_rover_colors) painter.setPen(red); - int y_labels_offset_x = -(fm.width(y_label)); - int y_labels_offset_y = fm.height()/3; + if (display_gps_data) painter.drawPoints(&scaled_gps_rover_points[0], scaled_gps_rover_points.size()); + // if (display_gps_data) painter.drawPath(scaled_gps_rover_path); - painter.drawText(x_axis_ticks[i].x()+x_labels_offset_x, axes_origin.y()+x_labels_offset_y, x_label); - painter.drawText(axes_origin.x()+y_labels_offset_x, y_axis_ticks[i].y()+y_labels_offset_y, y_label); - } + if(!display_unique_rover_colors) painter.setPen(Qt::white); - // End draw scale bars + if (display_ekf_data) painter.drawPath(scaled_ekf_rover_path); - // Repeat the display code for each rover selected by the user - Using C++11 range syntax - for(auto rover_to_display : display_list) + if(!display_unique_rover_colors) painter.setPen(green); + + if (display_encoder_data) painter.drawPath(scaled_encoder_rover_path); + + painter.setPen(red); + QPoint* point_array = &scaled_collection_points[0]; + painter.drawPoints(point_array, scaled_collection_points.size()); + + painter.setPen(green); + point_array = &scaled_target_locations[0]; + painter.drawPoints(point_array, scaled_target_locations.size()); + + // Draw a yellow circle at the current EKF estimated rover location + if(!map_data->getEKFPath(rover_to_display)->empty()) { - // scale coordinates - - std::vector scaled_target_locations; - for(std::vector< pair >::iterator it = map_data->getTargetLocations(rover_to_display)->begin(); it < map_data->getTargetLocations(rover_to_display)->end(); ++it) { - pair coordinate = *it; - QPoint point; - point.setX(map_origin_x+coordinate.first*map_width); - point.setY(map_origin_y+coordinate.second*map_height); - scaled_target_locations.push_back(point); - } - - std::vector scaled_collection_points; - for(std::vector< pair >::iterator it = map_data->getCollectionPoints(rover_to_display)->begin(); it < map_data->getCollectionPoints(rover_to_display)->end(); ++it) { - pair coordinate = *it; - QPoint point; - point.setX(map_origin_x+coordinate.first*map_width); - point.setY(map_origin_y+coordinate.second*map_height); - scaled_collection_points.push_back(point); - } - - std::vector scaled_gps_rover_points; - for(std::vector< pair >::iterator it = map_data->getGPSPath(rover_to_display)->begin(); it < map_data->getGPSPath(rover_to_display)->end(); ++it) { - pair coordinate = *it; - - float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); - float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - scaled_gps_rover_points.push_back( QPoint(x,y) ); - } - - QPainterPath scaled_ekf_rover_path; - for(std::vector< pair >::iterator it = map_data->getEKFPath(rover_to_display)->begin(); it < map_data->getEKFPath(rover_to_display)->end(); ++it) { - pair coordinate = *it; - QPoint point; - float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); - float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - - // Move to the starting point of the path without drawing a line - if (it == map_data->getEKFPath(rover_to_display)->begin()) scaled_ekf_rover_path.moveTo(x, y); - scaled_ekf_rover_path.lineTo(x, y); - } - - QPainterPath scaled_encoder_rover_path; - for(std::vector< pair >::iterator it = map_data->getEncoderPath(rover_to_display)->begin(); it < map_data->getEncoderPath(rover_to_display)->end(); ++it) { - - pair coordinate = *it; - QPoint point; - float x = map_origin_x+((coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); - float y = map_origin_y+((coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - - // Move to the starting point of the path without drawing a line - if (it == map_data->getEncoderPath(rover_to_display)->begin()) scaled_encoder_rover_path.moveTo(x, y); - - scaled_encoder_rover_path.lineTo(x, y); - } - - painter.setPen(red); - if (display_gps_data) painter.drawPoints(&scaled_gps_rover_points[0], scaled_gps_rover_points.size()); - // if (display_gps_data) painter.drawPath(scaled_gps_rover_path); - - painter.setPen(Qt::white); - if (display_ekf_data) painter.drawPath(scaled_ekf_rover_path); - painter.setPen(green); - if (display_encoder_data) painter.drawPath(scaled_encoder_rover_path); - - painter.setPen(red); - QPoint* point_array = &scaled_collection_points[0]; - painter.drawPoints(point_array, scaled_collection_points.size()); - painter.setPen(green); - point_array = &scaled_target_locations[0]; - painter.drawPoints(point_array, scaled_target_locations.size()); - - // Draw a yellow circle at the current EKF estimated rover location - if(!map_data->getEKFPath(rover_to_display)->empty()) { - painter.setPen(Qt::yellow); - pair current_coordinate; - current_coordinate = map_data->getEKFPath(rover_to_display)->back(); - - float x = map_origin_x+((current_coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); - float y = map_origin_y+((current_coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); - float radius = 2.5; - - painter.drawEllipse(QPointF(x,y), radius, radius); - painter.drawText(QPoint(x,y), QString::fromStdString(rover_to_display)); - } - - map_data->unlock(); - - painter.setPen(Qt::white); - } // End rover display list set iteration - - // Diagnostic output - /* - font.setPointSizeF( 12 ); - painter.drawText(QPoint(0,15), "min_seen_x: " + QString::number(min_seen_x)); - painter.drawText(QPoint(0,30), "min_seen_y: " + QString::number(min_seen_y)); - painter.drawText(QPoint(0,45), "max_width_seen: " + QString::number(max_seen_width)); - painter.drawText(QPoint(0,60), "max_height_seen: " + QString::number(max_seen_height)); - painter.drawText(QPoint(0,75), "map_origin_x: " + QString::number(map_origin_x)); - painter.drawText(QPoint(0,90), "map_origin_y: " + QString::number(map_origin_y)); - painter.drawText(QPoint(0,105), "map_width: " + QString::number(map_width)); - painter.drawText(QPoint(0,120), "map_height: " + QString::number(map_height)); - painter.drawText(QPoint(0,135), "map_center_x: " + QString::number(map_center_x)); - */ + if(display_unique_rover_colors) painter.setPen(rover_color); + else painter.setPen(Qt::yellow); + + pair current_coordinate; + current_coordinate = map_data->getEKFPath(rover_to_display)->back(); + + float x = map_origin_x+((current_coordinate.first-min_seen_x)/max_seen_width)*(map_width-map_origin_x); + float y = map_origin_y+((current_coordinate.second-min_seen_y)/max_seen_height)*(map_height-map_origin_y); + float radius = 2.5; + + painter.drawEllipse(QPointF(x,y), radius, radius); + painter.drawText(QPoint(x,y), QString::fromStdString(rover_to_display)); + } + + map_data->unlock(); painter.setPen(Qt::white); + + hardware_rover_color_index = (hardware_rover_color_index + 1) % 8; + + } // End rover display list set iteration + + // Diagnostic output + /* + font.setPointSizeF( 12 ); + painter.drawText(QPoint(0,15), "min_seen_x: " + QString::number(min_seen_x)); + painter.drawText(QPoint(0,30), "min_seen_y: " + QString::number(min_seen_y)); + painter.drawText(QPoint(0,45), "max_width_seen: " + QString::number(max_seen_width)); + painter.drawText(QPoint(0,60), "max_height_seen: " + QString::number(max_seen_height)); + painter.drawText(QPoint(0,75), "map_origin_x: " + QString::number(map_origin_x)); + painter.drawText(QPoint(0,90), "map_origin_y: " + QString::number(map_origin_y)); + painter.drawText(QPoint(0,105), "map_width: " + QString::number(map_width)); + painter.drawText(QPoint(0,120), "map_height: " + QString::number(map_height)); + painter.drawText(QPoint(0,135), "map_center_x: " + QString::number(map_center_x)); + */ + + painter.setPen(Qt::white); } void MapFrame::setDisplayEncoderData(bool display) { - display_encoder_data = display; + display_encoder_data = display; - if(popout_mapframe) popout_mapframe->setDisplayEncoderData(display); + if(popout_mapframe) popout_mapframe->setDisplayEncoderData(display); } void MapFrame::setDisplayGPSData(bool display) { - display_gps_data = display; + display_gps_data = display; - if(popout_mapframe) popout_mapframe->setDisplayGPSData(display); + if(popout_mapframe) popout_mapframe->setDisplayGPSData(display); } void MapFrame::setDisplayEKFData(bool display) { - display_ekf_data = display; + display_ekf_data = display; - if(popout_mapframe) popout_mapframe->setDisplayEKFData(display); + if(popout_mapframe) popout_mapframe->setDisplayEKFData(display); } -void MapFrame::setWhetherToDisplay(string rover, bool yes) +void MapFrame::setGlobalOffset(bool display) { - map_data->lock(); + display_global_offset = display; + map_data->setGlobalOffset(display); - if (yes) - { - display_list.insert(rover); - } - else - { - display_list.erase(rover); - } + if(popout_mapframe) popout_mapframe->setGlobalOffset(display); +} - map_data->unlock(); +void MapFrame::setGlobalOffsetForRover(string rover, float x, float y) +{ + map_data->setGlobalOffsetForRover(rover, x, y); +} + +void MapFrame::setDisplayUniqueRoverColors(bool display) +{ + display_unique_rover_colors = display; - if(popout_mapframe) popout_mapframe->setWhetherToDisplay(rover, yes); + if(popout_mapframe) popout_mapframe->setDisplayUniqueRoverColors(display); +} + +void MapFrame::setUniqueRoverColor(string rover, QColor rover_color) +{ + unique_rover_colors[rover] = rover_color; +} + +void MapFrame::setWhetherToDisplay(string rover, bool yes) +{ + map_data->lock(); + + if (yes) + { + display_list.insert(rover); + } + else + { + display_list.erase(rover); + } + + map_data->unlock(); + + if(popout_mapframe) popout_mapframe->setWhetherToDisplay(rover, yes); } void MapFrame::mouseReleaseEvent(QMouseEvent *event) { - previous_translate_x = translate_x; - previous_translate_y = translate_y; + previous_translate_x = translate_x; + previous_translate_y = translate_y; } void MapFrame::mousePressEvent(QMouseEvent *event) { - previous_clicked_position = event->pos(); - // emit sendInfoLogMessage("MapFrame: mouse press. x: " + QString::number(mouse_event->pos().x()) + ", y: " + QString::number(mouse_event->pos().y())); + previous_clicked_position = event->pos(); + // emit sendInfoLogMessage("MapFrame: mouse press. x: " + QString::number(mouse_event->pos().x()) + ", y: " + QString::number(mouse_event->pos().y())); } void MapFrame::mouseMoveEvent(QMouseEvent *event) { - // Do not adjust panning in auto-transform mode.. the changes will not be reflected - // and will be applied only when the user clicks on manual panning mode which will - // cause undesired results. - if (auto_transform == true) return; - - if (event->type() == QEvent::MouseMove) { - QMouseEvent* mouse_event = static_cast(event); - float max_width = this->width(); - float max_height = this->height(); - - // start with the previous translate - translate_x = previous_translate_x; - translate_y = previous_translate_y; - - // add the scaled translation based on the previous mouse click - // and the current mouse position while dragging; multiply the translation - // by the given translate speed to keep the map lined up with mouse movement - translate_x += translate_speed * (previous_clicked_position.x() - mouse_event->pos().x()) / max_width; - translate_y += translate_speed * (previous_clicked_position.y() - mouse_event->pos().y()) / max_height; - - // debug info log messages - // emit sendInfoLogMessage("MapFrame: mouse move: translate_x: " + QString::number(translate_x) + " translate_y: " + QString::number(translate_y) + "\n"); - // emit sendInfoLogMessage("MapFrame: mouse move: frame_width: " + QString::number(this->width()) + " frame_height: " + QString::number(this->height())); - // emit sendInfoLogMessage("MapFrame: mouse move: x: " + QString::number(mouse_event->pos().x()) + " y: " + QString::number(mouse_event->pos().y())); - // emit sendInfoLogMessage("MapFrame: mouse move: xp: " + QString::number(previous_clicked_position.x()) + " yp: " + QString::number(previous_clicked_position.y())); - } + // Do not adjust panning in auto-transform mode.. the changes will not be reflected + // and will be applied only when the user clicks on manual panning mode which will + // cause undesired results. + if (auto_transform == true) return; + + if (event->type() == QEvent::MouseMove) { + QMouseEvent* mouse_event = static_cast(event); + float max_width = this->width(); + float max_height = this->height(); + + // start with the previous translate + translate_x = previous_translate_x; + translate_y = previous_translate_y; + + // add the scaled translation based on the previous mouse click + // and the current mouse position while dragging; multiply the translation + // by the given translate speed to keep the map lined up with mouse movement + translate_x += translate_speed * (previous_clicked_position.x() - mouse_event->pos().x()) / max_width; + translate_y += translate_speed * (previous_clicked_position.y() - mouse_event->pos().y()) / max_height; + + // debug info log messages + // emit sendInfoLogMessage("MapFrame: mouse move: translate_x: " + QString::number(translate_x) + " translate_y: " + QString::number(translate_y) + "\n"); + // emit sendInfoLogMessage("MapFrame: mouse move: frame_width: " + QString::number(this->width()) + " frame_height: " + QString::number(this->height())); + // emit sendInfoLogMessage("MapFrame: mouse move: x: " + QString::number(mouse_event->pos().x()) + " y: " + QString::number(mouse_event->pos().y())); + // emit sendInfoLogMessage("MapFrame: mouse move: xp: " + QString::number(previous_clicked_position.x()) + " yp: " + QString::number(previous_clicked_position.y())); + } } void MapFrame::wheelEvent(QWheelEvent *event) { - // Do not adjust the zoom in auto-transform mode.. the changes will not be reflected - // and will be applied only when the user clicks on manual panning mode which will - // cause undesired results. - if (auto_transform == true) return; - - // 100% map zoom is set when scale = 10; 10% adjustments to - // the zoom occur with each mouse wheel adjustment - if (event->delta() < 0) { - scale++; - } else { - scale--; - } - - // limit the lower bound of the scale so we do not invert the map and have - // negative zoom values - if (scale <= 0) { - scale = 1; - // emit sendInfoLogMessage("Map Zoom Set: " + QString::number(scale * 10) + "% (Minimum Zoom)"); - } else { - // emit sendInfoLogMessage("Map Zoom Set: " + QString::number(scale * 10) + "%"); - } - - // debug info log messages - // emit sendInfoLogMessage("MapFrame: mouse wheel. Degrees: " + QString::number(num_degrees) + " Scale: " + QString::number(scale)); - // emit sendInfoLogMessage("MapFrame: mouse wheel. x: " + QString::number(event->pos().x()) + " y: " + QString::number(event->pos().y())); + // Do not adjust the zoom in auto-transform mode.. the changes will not be reflected + // and will be applied only when the user clicks on manual panning mode which will + // cause undesired results. + if (auto_transform == true) return; + + // 100% map zoom is set when scale = 10; 10% adjustments to + // the zoom occur with each mouse wheel adjustment + if (event->delta() < 0) { + scale++; + } else { + scale--; + } + + // limit the lower bound of the scale so we do not invert the map and have + // negative zoom values + if (scale <= 0) { + scale = 1; + // emit sendInfoLogMessage("Map Zoom Set: " + QString::number(scale * 10) + "% (Minimum Zoom)"); + } else { + // emit sendInfoLogMessage("Map Zoom Set: " + QString::number(scale * 10) + "%"); + } + + // debug info log messages + // emit sendInfoLogMessage("MapFrame: mouse wheel. Degrees: " + QString::number(num_degrees) + " Scale: " + QString::number(scale)); + // emit sendInfoLogMessage("MapFrame: mouse wheel. x: " + QString::number(event->pos().x()) + " y: " + QString::number(event->pos().y())); } void MapFrame::setManualTransform() { - if (popout_mapframe) popout_mapframe->setManualTransform(); - auto_transform = false; - - // Calculate and store the max and min values seen so far for use my the manual transform - float max_seen_x = -std::numeric_limits::max(); // std::numeric_limits::max() is the max possible floating point value - float max_seen_y = -std::numeric_limits::max(); - float min_seen_x = std::numeric_limits::max(); - float min_seen_y = std::numeric_limits::max(); - - for (auto rover_to_display : display_list) - { - if (display_ekf_data) - { - if (min_seen_x > map_data->getMinEKFX(rover_to_display)) min_seen_x = map_data->getMinEKFX(rover_to_display); - if (min_seen_y > map_data->getMinEKFY(rover_to_display)) min_seen_y = map_data->getMinEKFY(rover_to_display); - if (max_seen_x < map_data->getMaxEKFX(rover_to_display)) max_seen_x = map_data->getMaxEKFX(rover_to_display); - if (max_seen_y < map_data->getMaxEKFY(rover_to_display)) max_seen_y = map_data->getMaxEKFY(rover_to_display); - } - - if (display_gps_data) - { - if (min_seen_x > map_data->getMinGPSX(rover_to_display)) min_seen_x = map_data->getMinGPSX(rover_to_display); - if (min_seen_y > map_data->getMinGPSY(rover_to_display)) min_seen_y = map_data->getMinGPSY(rover_to_display); - if (max_seen_x < map_data->getMaxGPSX(rover_to_display)) max_seen_x = map_data->getMaxGPSX(rover_to_display); - if (max_seen_y < map_data->getMaxGPSY(rover_to_display)) max_seen_y = map_data->getMaxGPSY(rover_to_display); - } - - if (display_encoder_data) - { - if (min_seen_x > map_data->getMinEncoderX(rover_to_display)) min_seen_x = map_data->getMinEncoderX(rover_to_display); - if (min_seen_y > map_data->getMinEncoderY(rover_to_display)) min_seen_y = map_data->getMinEncoderY(rover_to_display); - if (max_seen_x < map_data->getMaxEncoderX(rover_to_display)) max_seen_x = map_data->getMaxEncoderX(rover_to_display); - if (max_seen_y < map_data->getMaxEncoderY(rover_to_display)) max_seen_y = map_data->getMaxEncoderY(rover_to_display); - } - } - - // Normalize the displayed coordinates to the largest coordinates seen since we don't know the coordinate system. - float max_seen_width = max_seen_x-min_seen_x; - float max_seen_height = max_seen_y-min_seen_y; - min_seen_x_when_manual_enabled = min_seen_x; - min_seen_y_when_manual_enabled = min_seen_y; - max_seen_width_when_manual_enabled = max_seen_width; - max_seen_height_when_manual_enabled = max_seen_height; - - /* scale the translate speed with the max seen width and height */ - translate_speed = (max_seen_width * 0.75) + (max_seen_height * 0.75); + if (popout_mapframe) popout_mapframe->setManualTransform(); + auto_transform = false; + + // Calculate and store the max and min values seen so far for use my the manual transform + float max_seen_x = -std::numeric_limits::max(); // std::numeric_limits::max() is the max possible floating point value + float max_seen_y = -std::numeric_limits::max(); + float min_seen_x = std::numeric_limits::max(); + float min_seen_y = std::numeric_limits::max(); + + for (auto rover_to_display : display_list) + { + if (display_ekf_data) + { + if (min_seen_x > map_data->getMinEKFX(rover_to_display)) min_seen_x = map_data->getMinEKFX(rover_to_display); + if (min_seen_y > map_data->getMinEKFY(rover_to_display)) min_seen_y = map_data->getMinEKFY(rover_to_display); + if (max_seen_x < map_data->getMaxEKFX(rover_to_display)) max_seen_x = map_data->getMaxEKFX(rover_to_display); + if (max_seen_y < map_data->getMaxEKFY(rover_to_display)) max_seen_y = map_data->getMaxEKFY(rover_to_display); + } + + if (display_gps_data) + { + if (min_seen_x > map_data->getMinGPSX(rover_to_display)) min_seen_x = map_data->getMinGPSX(rover_to_display); + if (min_seen_y > map_data->getMinGPSY(rover_to_display)) min_seen_y = map_data->getMinGPSY(rover_to_display); + if (max_seen_x < map_data->getMaxGPSX(rover_to_display)) max_seen_x = map_data->getMaxGPSX(rover_to_display); + if (max_seen_y < map_data->getMaxGPSY(rover_to_display)) max_seen_y = map_data->getMaxGPSY(rover_to_display); + } + + if (display_encoder_data) + { + if (min_seen_x > map_data->getMinEncoderX(rover_to_display)) min_seen_x = map_data->getMinEncoderX(rover_to_display); + if (min_seen_y > map_data->getMinEncoderY(rover_to_display)) min_seen_y = map_data->getMinEncoderY(rover_to_display); + if (max_seen_x < map_data->getMaxEncoderX(rover_to_display)) max_seen_x = map_data->getMaxEncoderX(rover_to_display); + if (max_seen_y < map_data->getMaxEncoderY(rover_to_display)) max_seen_y = map_data->getMaxEncoderY(rover_to_display); + } + } + + // Normalize the displayed coordinates to the largest coordinates seen since we don't know the coordinate system. + float max_seen_width = max_seen_x-min_seen_x; + float max_seen_height = max_seen_y-min_seen_y; + min_seen_x_when_manual_enabled = min_seen_x; + min_seen_y_when_manual_enabled = min_seen_y; + max_seen_width_when_manual_enabled = max_seen_width; + max_seen_height_when_manual_enabled = max_seen_height; + + /* scale the translate speed with the max seen width and height */ + translate_speed = (max_seen_width * 0.75) + (max_seen_height * 0.75); } void MapFrame::setAutoTransform() { - if (popout_mapframe) popout_mapframe->setAutoTransform(); - auto_transform = true; - scale = 10; - translate_x = 0.0f; - translate_y = 0.0f; - previous_translate_x = 0.0f; - previous_translate_y = 0.0f; - previous_clicked_position = QPoint(0,0); + if (popout_mapframe) popout_mapframe->setAutoTransform(); + auto_transform = true; + scale = 10; + translate_x = 0.0f; + translate_y = 0.0f; + previous_translate_x = 0.0f; + previous_translate_y = 0.0f; + previous_clicked_position = QPoint(0,0); } void MapFrame::clear() { - map_data->lock(); - display_list.clear(); - map_data->unlock(); + map_data->lock(); + display_list.clear(); + map_data->unlock(); } void MapFrame::clear(string rover) { - map_data->lock(); - display_list.erase(rover); - map_data->unlock(); + map_data->lock(); + display_list.erase(rover); + map_data->unlock(); } void MapFrame::popout() { - if (popout_window) popout_window->show(); + if (popout_window) popout_window->show(); } void MapFrame::setMapData(MapData* data) { - map_data = data; + map_data = data; } void MapFrame::addToGPSRoverPath(std::string rover, float x, float y) { - if (map_data) - { - map_data->addToGPSRoverPath(rover, x, y); - emit delayedUpdate(); - } + if (map_data) + { + map_data->addToGPSRoverPath(rover, x, y); + emit delayedUpdate(); + } } void MapFrame::addToEncoderRoverPath(std::string rover, float x, float y) { - if (map_data) - { - map_data->addToEncoderRoverPath(rover, x, y); - emit delayedUpdate(); - } + if (map_data) + { + map_data->addToEncoderRoverPath(rover, x, y); + emit delayedUpdate(); + } } void MapFrame::addToEKFRoverPath(std::string rover, float x, float y) { - if (map_data) - { - map_data->addToEKFRoverPath(rover, x, y); - emit delayedUpdate(); - } + if (map_data) + { + map_data->addToEKFRoverPath(rover, x, y); + emit delayedUpdate(); + } } MapFrame::~MapFrame() { - // Safely erase map data - locks to make sure a frame isnt being drawn - // clearMap(); - if (popout_window) delete popout_window; + // Safely erase map data - locks to make sure a frame isnt being drawn + // clearMap(); + if (popout_window) delete popout_window; } } diff --git a/src/rqt_rover_gui/src/MapFrame.h b/src/rqt_rover_gui/src/MapFrame.h index 194ec28d..c394fab6 100644 --- a/src/rqt_rover_gui/src/MapFrame.h +++ b/src/rqt_rover_gui/src/MapFrame.h @@ -51,6 +51,10 @@ namespace rqt_rover_gui void setDisplayEncoderData(bool display); void setDisplayGPSData(bool display); void setDisplayEKFData(bool display); + void setGlobalOffset(bool display); + void setGlobalOffsetForRover(std::string rover, float x, float y); + void setDisplayUniqueRoverColors(bool display); + void setUniqueRoverColor(std::string, QColor rover_color); void addToGPSRoverPath(std::string rover, float x, float y); void addToEncoderRoverPath(std::string rover, float x, float y); @@ -100,11 +104,23 @@ namespace rqt_rover_gui bool display_gps_data; bool display_ekf_data; bool display_encoder_data; + bool display_global_offset; + bool display_unique_rover_colors; QTime frame_rate_timer; int frames; set display_list; + std::map unique_rover_colors; + std::map unique_simulated_rover_colors; + QColor unique_physical_rover_colors[8] = { /* green */ QColor( 0, 255, 0), + /* yellow */ QColor(255, 255, 0), + /* white */ QColor(255, 255, 255), + /* red */ QColor(255, 0, 0), + /* deep sky blue */ QColor( 0, 191, 255), + /* hot pink */ QColor(255, 105, 180), + /* chocolate */ QColor(210, 105, 30), + /* indigo */ QColor( 75, 0, 130) }; // For external pop out window QMainWindow* popout_window; diff --git a/src/rqt_rover_gui/src/rover_gui_plugin.cpp b/src/rqt_rover_gui/src/rover_gui_plugin.cpp index 778099bc..7354bebe 100644 --- a/src/rqt_rover_gui/src/rover_gui_plugin.cpp +++ b/src/rqt_rover_gui/src/rover_gui_plugin.cpp @@ -124,6 +124,8 @@ namespace rqt_rover_gui connect(ui.ekf_checkbox, SIGNAL(toggled(bool)), this, SLOT(EKFCheckboxToggledEventHandler(bool))); connect(ui.gps_checkbox, SIGNAL(toggled(bool)), this, SLOT(GPSCheckboxToggledEventHandler(bool))); connect(ui.encoder_checkbox, SIGNAL(toggled(bool)), this, SLOT(encoderCheckboxToggledEventHandler(bool))); + connect(ui.global_offset_checkbox, SIGNAL(toggled(bool)), this, SLOT(globalOffsetCheckboxToggledEventHandler(bool))); + connect(ui.unique_rover_colors_checkbox, SIGNAL(toggled(bool)), this, SLOT(uniqueRoverColorsCheckboxToggledEventHandler(bool))); connect(ui.autonomous_control_radio_button, SIGNAL(toggled(bool)), this, SLOT(autonomousRadioButtonEventHandler(bool))); connect(ui.joystick_control_radio_button, SIGNAL(toggled(bool)), this, SLOT(joystickRadioButtonEventHandler(bool))); connect(ui.all_autonomous_button, SIGNAL(pressed()), this, SLOT(allAutonomousButtonEventHandler())); @@ -155,9 +157,13 @@ namespace rqt_rover_gui connect(this, SIGNAL(updateNumberOfSatellites(QString)), ui.gps_numSV_label, SLOT(setText(QString))); connect(this, SIGNAL(sendInfoLogMessage(QString)), this, SLOT(receiveInfoLogMessage(QString))); connect(this, SIGNAL(sendDiagLogMessage(QString)), this, SLOT(receiveDiagLogMessage(QString))); + connect(ui.custom_world_path_button, SIGNAL(pressed()), this, SLOT(customWorldButtonEventHandler())); connect(ui.custom_distribution_radio_button, SIGNAL(toggled(bool)), this, SLOT(customWorldRadioButtonEventHandler(bool))); + connect(ui.powerlaw_distribution_radio_button, SIGNAL(toggled(bool)), this, SLOT(powerlawDistributionRadioButtonEventHandler(bool))); + connect(ui.unbounded_radio_button, SIGNAL(toggled(bool)), this, SLOT(unboundedRadioButtonEventHandler(bool))); connect(ui.override_num_rovers_checkbox, SIGNAL(toggled(bool)), this, SLOT(overrideNumRoversCheckboxToggledEventHandler(bool))); + connect(ui.create_savable_world_checkbox, SIGNAL(toggled(bool)), this, SLOT(createSavableWorldCheckboxToggledEventHandler(bool))); // Receive log messages from contained frames connect(ui.map_frame, SIGNAL(sendInfoLogMessage(QString)), this, SLOT(receiveInfoLogMessage(QString))); @@ -211,7 +217,7 @@ namespace rqt_rover_gui info_log_subscriber = nh.subscribe("/infoLog", 10, &RoverGUIPlugin::infoLogMessageEventHandler, this); diag_log_subscriber = nh.subscribe("/diagsLog", 10, &RoverGUIPlugin::diagLogMessageEventHandler, this); - emit updateNumberOfSatellites("Number of GPS Satellites: ---"); + emit updateNumberOfSatellites("---"); } void RoverGUIPlugin::shutdownPlugin() @@ -429,10 +435,10 @@ void RoverGUIPlugin::GPSNavSolutionEventHandler(const ros::MessageEvent 0 if (selected_rover_name.compare("") != 0 && msg.get()->numSV > 0) { // Update the label in the GUI with the selected rover's information - QString newLabelText = "Number of GPS Satellites: " + QString::number(rover_numSV_state[selected_rover_name]); + QString newLabelText = QString::number(rover_numSV_state[selected_rover_name]); emit updateNumberOfSatellites("" + newLabelText + ""); } else { - emit updateNumberOfSatellites("Number of GPS Satellites: ---"); + emit updateNumberOfSatellites("---"); } } @@ -674,10 +680,10 @@ void RoverGUIPlugin::currentRoverChangedEventHandler(QListWidgetItem *current, Q // only update the number of satellites if a valid rover name has been selected if (selected_rover_name.compare("") != 0 && rover_numSV_state[selected_rover_name] > 0) { - QString newLabelText = "Number of GPS Satellites: " + QString::number(rover_numSV_state[selected_rover_name]); + QString newLabelText = QString::number(rover_numSV_state[selected_rover_name]); emit updateNumberOfSatellites("" + newLabelText + ""); } else { - emit updateNumberOfSatellites("Number of GPS Satellites: ---"); + emit updateNumberOfSatellites("---"); } // Enable control mode radio group now that a rover has been selected @@ -1132,6 +1138,16 @@ void RoverGUIPlugin::encoderCheckboxToggledEventHandler(bool checked) ui.map_frame->setDisplayEncoderData(checked); } +void RoverGUIPlugin::globalOffsetCheckboxToggledEventHandler(bool checked) +{ + ui.map_frame->setGlobalOffset(checked); +} + +void RoverGUIPlugin::uniqueRoverColorsCheckboxToggledEventHandler(bool checked) +{ + ui.map_frame->setDisplayUniqueRoverColors(checked); +} + void RoverGUIPlugin::displayDiagLogMessage(QString msg) { if (msg.isEmpty()) msg = "Message is empty"; @@ -1316,20 +1332,20 @@ void RoverGUIPlugin::allAutonomousButtonEventHandler() ui.autonomous_control_radio_button->setChecked(true); ui.joystick_frame->setHidden(true); - //Disable all autonomous button + // Disable all autonomous button ui.all_autonomous_button->setEnabled(false); ui.all_autonomous_button->setStyleSheet("color: grey; border:2px solid grey;"); - //Experiment Timer START + // Experiment Timer START // this catches the case when the /clock timer is not running // AKA: when we are not running a simulation if (current_simulated_time_in_seconds > 0.0) { - if (ui.simulation_timer_combo_box->currentText() == "no time limit") { + if (ui.simulation_timer_combobox->currentText() == "no time limit") { timer_start_time_in_seconds = 0.0; timer_stop_time_in_seconds = 0.0; is_timer_on = false; - } else if (ui.simulation_timer_combo_box->currentText() == "10 min (Testing)") { + } else if (ui.simulation_timer_combobox->currentText() == "10 min (Testing)") { timer_start_time_in_seconds = current_simulated_time_in_seconds; timer_stop_time_in_seconds = timer_start_time_in_seconds + 600.0; is_timer_on = true; @@ -1349,9 +1365,31 @@ void RoverGUIPlugin::allAutonomousButtonEventHandler() QString::number(getHours(timer_stop_time_in_seconds)) + " hours, " + QString::number(getMinutes(timer_stop_time_in_seconds)) + " minutes, " + QString::number(floor(getSeconds(timer_stop_time_in_seconds))) + " seconds"); - ui.simulation_timer_combo_box->setEnabled(false); - ui.simulation_timer_combo_box->setStyleSheet("color: grey; border:2px solid grey;"); - } else if (ui.simulation_timer_combo_box->currentText() == "30 min (Preliminary)") { + ui.simulation_timer_combobox->setEnabled(false); + ui.simulation_timer_combobox->setStyleSheet("color: grey; border:2px solid grey;"); + } else if (ui.simulation_timer_combobox->currentText() == "20 min (Preliminary)") { + timer_start_time_in_seconds = current_simulated_time_in_seconds; + timer_stop_time_in_seconds = timer_start_time_in_seconds + 1200.0; + is_timer_on = true; + emit sendInfoLogMessage("\nSetting experiment timer to start at: " + + QString::number(getHours(timer_start_time_in_seconds)) + " hours, " + + QString::number(getMinutes(timer_start_time_in_seconds)) + " minutes, " + + QString::number(getSeconds(timer_start_time_in_seconds)) + " seconds"); + ui.simulationTimerStartLabel->setText("" + + QString::number(getHours(timer_start_time_in_seconds)) + " hours, " + + QString::number(getMinutes(timer_start_time_in_seconds)) + " minutes, " + + QString::number(floor(getSeconds(timer_start_time_in_seconds))) + " seconds"); + emit sendInfoLogMessage("Setting experiment timer to stop at: " + + QString::number(getHours(timer_stop_time_in_seconds)) + " hours, " + + QString::number(getMinutes(timer_stop_time_in_seconds)) + " minutes, " + + QString::number(getSeconds(timer_stop_time_in_seconds)) + " seconds\n"); + ui.simulationTimerStopLabel->setText("" + + QString::number(getHours(timer_stop_time_in_seconds)) + " hours, " + + QString::number(getMinutes(timer_stop_time_in_seconds)) + " minutes, " + + QString::number(floor(getSeconds(timer_stop_time_in_seconds))) + " seconds"); + ui.simulation_timer_combobox->setEnabled(false); + ui.simulation_timer_combobox->setStyleSheet("color: grey; border:2px solid grey;"); + } else if (ui.simulation_timer_combobox->currentText() == "30 min (Preliminary)") { timer_start_time_in_seconds = current_simulated_time_in_seconds; timer_stop_time_in_seconds = timer_start_time_in_seconds + 1800.0; is_timer_on = true; @@ -1371,9 +1409,9 @@ void RoverGUIPlugin::allAutonomousButtonEventHandler() QString::number(getHours(timer_stop_time_in_seconds)) + " hours, " + QString::number(getMinutes(timer_stop_time_in_seconds)) + " minutes, " + QString::number(floor(getSeconds(timer_stop_time_in_seconds))) + " seconds"); - ui.simulation_timer_combo_box->setEnabled(false); - ui.simulation_timer_combo_box->setStyleSheet("color: grey; border:2px solid grey;"); - } else if (ui.simulation_timer_combo_box->currentText() == "60 min (Final)") { + ui.simulation_timer_combobox->setEnabled(false); + ui.simulation_timer_combobox->setStyleSheet("color: grey; border:2px solid grey;"); + } else if (ui.simulation_timer_combobox->currentText() == "60 min (Final)") { timer_start_time_in_seconds = current_simulated_time_in_seconds; timer_stop_time_in_seconds = timer_start_time_in_seconds + 3600.0; is_timer_on = true; @@ -1393,11 +1431,12 @@ void RoverGUIPlugin::allAutonomousButtonEventHandler() QString::number(getHours(timer_stop_time_in_seconds)) + " hours, " + QString::number(getMinutes(timer_stop_time_in_seconds)) + " minutes, " + QString::number(floor(getSeconds(timer_stop_time_in_seconds))) + " seconds"); - ui.simulation_timer_combo_box->setEnabled(false); - ui.simulation_timer_combo_box->setStyleSheet("color: grey; border:2px solid grey;"); + ui.simulation_timer_combobox->setEnabled(false); + ui.simulation_timer_combobox->setStyleSheet("color: grey; border:2px solid grey;"); } } - //Experiment Timer END + + // Experiment Timer END } double RoverGUIPlugin::getHours(double seconds) { @@ -1477,8 +1516,8 @@ void RoverGUIPlugin::allStopButtonEventHandler() ui.all_stop_button->setStyleSheet("color: grey; border:2px solid grey;"); // reset the simulation timer variables - ui.simulation_timer_combo_box->setEnabled(true); - ui.simulation_timer_combo_box->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); + ui.simulation_timer_combobox->setEnabled(true); + ui.simulation_timer_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); ui.simulationTimerStartLabel->setText("---"); ui.simulationTimerStopLabel->setText("---"); timer_start_time_in_seconds = 0.0; @@ -1521,18 +1560,61 @@ void RoverGUIPlugin::customWorldButtonEventHandler() void RoverGUIPlugin::customWorldRadioButtonEventHandler(bool toggled) { ui.custom_world_path_button->setEnabled(toggled); + ui.number_of_tags_combobox->setEnabled(!toggled); // Set the button color to reflect whether or not it is disabled // Clear the sim path if custom distribution it deselected - if( toggled ) + if(toggled) { ui.custom_world_path_button->setStyleSheet("color: white; border:2px solid white;"); + + ui.number_of_tags_label->setStyleSheet("color: grey;"); + ui.number_of_tags_combobox->setStyleSheet("color: grey; border:2px solid grey; padding: 1px 0px 1px 3px"); } else { sim_mgr.setCustomWorldPath(""); ui.custom_world_path->setText(""); ui.custom_world_path_button->setStyleSheet("color: grey; border:2px solid grey;"); + + ui.number_of_tags_label->setStyleSheet("color: white;"); + ui.number_of_tags_combobox->setStyleSheet("color: white; border:2px solid white; padding: 1px 0px 1px 3px"); + } +} + +// Currently, we cannot use the power law distribution with custon numbers of cubes. +// I.E., we always use 256 tags, so disable the option to change the number of cubes when +// generating a power law distribution. If we add dynamic power law distribution generation +// in the future this block can be removed. +void RoverGUIPlugin::powerlawDistributionRadioButtonEventHandler(bool toggled) +{ + ui.number_of_tags_combobox->setEnabled(!toggled); + + if(!toggled) + { + ui.number_of_tags_label->setStyleSheet("color: white;"); + ui.number_of_tags_combobox->setStyleSheet("color: white; border:2px solid white; padding: 1px 0px 1px 3px"); + } + else + { + ui.number_of_tags_label->setStyleSheet("color: grey;"); + ui.number_of_tags_combobox->setStyleSheet("color: grey; border:2px solid grey; padding: 1px 0px 1px 3px"); + } +} + +void RoverGUIPlugin::unboundedRadioButtonEventHandler(bool toggled) +{ + ui.unbounded_arena_size_combobox->setEnabled(toggled); + + if(toggled) + { + ui.unbounded_arena_size_label->setStyleSheet("color: white;"); + ui.unbounded_arena_size_combobox->setStyleSheet("color: white; border:2px solid white; padding: 1px 0px 1px 3px"); + } + else + { + ui.unbounded_arena_size_label->setStyleSheet("color: grey;"); + ui.unbounded_arena_size_combobox->setStyleSheet("color: grey; border:2px solid grey; padding: 1px 0px 1px 3px"); } } @@ -1559,199 +1641,252 @@ void RoverGUIPlugin::buildSimulationButtonEventHandler() QProcess* sim_server_process = sim_mgr.startGazeboServer(); connect(sim_server_process, SIGNAL(finished(int)), this, SLOT(gazeboServerFinishedEventHandler())); - - if (ui.final_radio_button->isChecked()) + if (ui.final_radio_button->isChecked() && !ui.create_savable_world_checkbox->isChecked()) { arena_dim = 23.1; addFinalsWalls(); + emit sendInfoLogMessage(QString("Set arena size to ")+QString::number(arena_dim)+"x"+QString::number(arena_dim)); } - else + else if (ui.prelim_radio_button->isChecked() && !ui.create_savable_world_checkbox->isChecked()) { arena_dim = 15; addPrelimsWalls(); + emit sendInfoLogMessage(QString("Set arena size to ")+QString::number(arena_dim)+"x"+QString::number(arena_dim)); + } + else + { + arena_dim = ui.unbounded_arena_size_combobox->currentText().toInt(); + emit sendInfoLogMessage(QString("Set arena size to ")+QString::number(arena_dim)+"x"+QString::number(arena_dim)+" with no barriers"); } - emit sendInfoLogMessage(QString("Set arena size to ")+QString::number(arena_dim)+"x"+QString::number(arena_dim)); - - if (ui.texture_combobox->currentText() == "Gravel") + if(!ui.create_savable_world_checkbox->isChecked()) { - emit sendInfoLogMessage("Adding gravel ground plane..."); - return_msg = sim_mgr.addGroundPlane("mars_ground_plane"); - emit sendInfoLogMessage(return_msg); + if (ui.texture_combobox->currentText() == "Gravel") + { + emit sendInfoLogMessage("Adding gravel ground plane..."); + return_msg = sim_mgr.addGroundPlane("mars_ground_plane"); + emit sendInfoLogMessage(return_msg); + } + else if (ui.texture_combobox->currentText() == "KSC Concrete") + { + emit sendInfoLogMessage("Adding concrete ground plane..."); + return_msg = sim_mgr.addGroundPlane("concrete_ground_plane"); + emit sendInfoLogMessage(return_msg); + } + else if (ui.texture_combobox->currentText() == "Car park") + { + emit sendInfoLogMessage("Adding carpark ground plane..."); + return_msg = sim_mgr.addGroundPlane("carpark_ground_plane"); + emit sendInfoLogMessage(return_msg); + } + else + { + emit sendInfoLogMessage("Unknown ground plane..."); + } } - else if (ui.texture_combobox->currentText() == "KSC Concrete") + else { - emit sendInfoLogMessage("Adding concrete ground plane..."); - return_msg = sim_mgr.addGroundPlane("concrete_ground_plane"); - emit sendInfoLogMessage(return_msg); + emit sendInfoLogMessage("Not using a ground plane texture..."); } - else if (ui.texture_combobox->currentText() == "Car park") + + if(!ui.create_savable_world_checkbox->isChecked()) { - emit sendInfoLogMessage("Adding carpark ground plane..."); - return_msg = sim_mgr.addGroundPlane("carpark_ground_plane"); - emit sendInfoLogMessage(return_msg); + emit sendInfoLogMessage("Adding collection disk..."); + float collection_disk_radius = 0.5; // meters + sim_mgr.addModel("collection_disk", "collection_disk", 0, 0, 0, collection_disk_radius); + score_subscriber = nh.subscribe("/collectionZone/score", 10, &RoverGUIPlugin::scoreEventHandler, this); + simulation_timer_subscriber = nh.subscribe("/clock", 10, &RoverGUIPlugin::simulationTimerEventHandler, this); } else { - emit sendInfoLogMessage("Unknown ground plane..."); + emit sendInfoLogMessage("Not adding collection disk..."); } + if(!ui.create_savable_world_checkbox->isChecked()) + { + int n_rovers_created = 0; + int n_rovers = 3; + if (ui.final_radio_button->isChecked()) n_rovers = 6; + + // If the user chose to override the number of rovers to add to the simulation read the selected value + // Please notice that this will override "n_rovers = 6" above if the final radio button is selected + if (ui.override_num_rovers_checkbox->isChecked()) n_rovers = ui.custom_num_rovers_combobox->currentText().toInt(); + + QProgressDialog progress_dialog; + progress_dialog.setWindowTitle("Creating rovers"); + progress_dialog.setCancelButton(NULL); // no cancel button + progress_dialog.setWindowModality(Qt::ApplicationModal); + progress_dialog.setWindowFlags(progress_dialog.windowFlags() | Qt::WindowStaysOnTopHint); + progress_dialog.resize(500, 50); + progress_dialog.show(); + + QString rovers[8] = {"achilles", "aeneas", "ajax", "diomedes", "hector", "paris", "thor", "zeus"}; + + QColor rover_colors[8] = { /* green */ QColor( 0, 255, 0), + /* yellow */ QColor(255, 255, 0), + /* white */ QColor(255, 255, 255), + /* red */ QColor(255, 0, 0), + /* deep sky blue */ QColor( 0, 191, 255), + /* hot pink */ QColor(255, 105, 180), + /* chocolate */ QColor(210, 105, 30), + /* indigo */ QColor( 75, 0, 130) }; + + /** + * The distance to the rover from a corner position is calculated differently + * than the distance to a cardinal position. + * + * The cardinal direction rovers are a straightforward calculation where: + * a = the distance to the edge of the collection zone + * i.e., 1/2 of the collection zone square side length + * b = the 50cm distance required by the rules for placing the rover + * c = offset for the simulation for the center of the rover (30cm) + * i.e., the rover position is at the center of its body + * + * The corner rovers use trigonometry to calculate the distance where each + * value of d, e, and f, are the legs to an isosceles right triangle. In + * other words, we are calculating and summing X and Y offsets to position + * the rover. + * d = a + * e = xy offset to move the rover 50cm from the corner of the collection zone + * f = xy offset to move the rover 30cm to account for its position being + * calculated at the center of its body + * + * * * d = 0.508m + * * * e = 0.354m + * * * + f = 0.212m + * * /* * ------------ + * * / | f * 1.072m + * * /--| * + * /* * + * / | e + * /--| + * ************* + * * /| + * * / | + * * / | d a = 0.508m + * * / | ********* b = 0.500m + * * / | * * + c = 0.300m + * * *-----|-----*---* * ------------ + * * a * b * c * 1.308m + * * * ********* + * * * + * * * + * * * + * ************* + */ + QPointF rover_positions[8] = + { + /* cardinal rovers: North, East, South, West */ + QPointF(-1.308, 0.000), // 1.308 = distance_from_center_to_edge_of_collection_zone + QPointF( 0.000, -1.308), // + 50 cm distance to rover + QPointF( 1.308, 0.000), // + 30 cm distance_from_center_of_rover_to_edge_of_rover + QPointF( 0.000, 1.308), // 1.308m = 0.508m + 0.5m + 0.3m + + /* corner rovers: Northeast, Southwest */ + QPointF( 1.072, 1.072), // 1.072 = diagonal_distance_from_center_to_edge_of_collection_zone + QPointF(-1.072, -1.072), // + diagonal_distance_to_move_50cm + // + diagonal_distance_to_move_30cm + // 1.072m = 0.508 + 0.354 + 0.212 + + /* corner rovers: Northwest, Southeast */ + QPointF(-1.072, 1.072), + QPointF( 1.072, -1.072) + }; + + /* In this case, the yaw is the value that turns rover "left" and "right" */ + float rover_yaw[8] = + { + 0.000, // 0.00 * PI + 1.571, // 0.50 * PI + -3.142, // -1.00 * PI + -1.571, // -0.50 * PI + -2.356, // -0.75 * PI + 0.785, // 0.25 * PI + -0.785, // -0.25 * PI + 2.356 // 0.75 * PI + }; + + // Add rovers to the simulation and start the associated ROS nodes + for (int i = 0; i < n_rovers; i++) + { + // add the global offset for sim rovers + ui.map_frame->setGlobalOffsetForRover(rovers[i].toStdString(), rover_positions[i].x(), rover_positions[i].y()); + ui.map_frame->setUniqueRoverColor(rovers[i].toStdString(), rover_colors[i]); - emit sendInfoLogMessage("Adding collection disk..."); - float collection_disk_radius = 0.5; // meters - sim_mgr.addModel("collection_disk", "collection_disk", 0, 0, 0, collection_disk_radius); - score_subscriber = nh.subscribe("/collectionZone/score", 10, &RoverGUIPlugin::scoreEventHandler, this); - simulation_timer_subscriber = nh.subscribe("/clock", 10, &RoverGUIPlugin::simulationTimerEventHandler, this); - - int n_rovers_created = 0; - int n_rovers = 3; - if (ui.final_radio_button->isChecked()) n_rovers = 6; + emit sendInfoLogMessage("Adding rover "+rovers[i]+"..."); + return_msg = sim_mgr.addRover(rovers[i], rover_positions[i].x(), rover_positions[i].y(), 0, 0, 0, rover_yaw[i]); + emit sendInfoLogMessage(return_msg); - // If the user chose to override the number of rovers to add to the simulation read the selected value - if (ui.override_num_rovers_checkbox->isChecked()) n_rovers = ui.custom_num_rovers_combobox->currentText().toInt(); + emit sendInfoLogMessage("Starting rover node for "+rovers[i]+"..."); + return_msg = sim_mgr.startRoverNode(rovers[i]); + emit sendInfoLogMessage(return_msg); - QProgressDialog progress_dialog; - progress_dialog.setWindowTitle("Creating rovers"); - progress_dialog.setCancelButton(NULL); // no cancel button - progress_dialog.setWindowModality(Qt::ApplicationModal); - progress_dialog.setWindowFlags(progress_dialog.windowFlags() | Qt::WindowStaysOnTopHint); - progress_dialog.resize(500, 50); - progress_dialog.show(); - - QString rovers[6] = {"achilles", "aeneas", "ajax", "diomedes", "hector", "paris"}; - - /** - * The distance to the rover from a corner position is calculated differently - * than the distance to a cardinal position. - * - * The cardinal direction rovers are a straightforward calculation where: - * a = the distance to the edge of the collection zone - * i.e., 1/2 of the collection zone square side length - * b = the 50cm distance required by the rules for placing the rover - * c = offset for the simulation for the center of the rover (30cm) - * i.e., the rover position is at the center of its body - * - * The corner rovers use trigonometry to calculate the distance where each - * value of d, e, and f, are the legs to an isosceles right triangle. In - * other words, we are calculating and summing X and Y offsets to position - * the rover. - * d = a - * e = xy offset to move the rover 50cm from the corner of the collection zone - * f = xy offset to move the rover 30cm to account for its position being - * calculated at the center of its body - * - * * * d = 0.508m - * * * e = 0.354m - * * * + f = 0.212m - * * /* * ------------ - * * / | f * 1.072m - * * /--| * - * /* * - * / | e - * /--| - * ************* - * * /| - * * / | - * * / | d a = 0.508m - * * / | ********* b = 0.500m - * * / | * * + c = 0.300m - * * *-----|-----*---* * ------------ - * * a * b * c * 1.308m - * * * ********* - * * * - * * * - * * * - * ************* - */ - QPointF rover_positions[6] = - { - /* cardinal rovers: North, East, South, West */ - QPointF(-1.308, 0.000), // 1.308 = distance_from_center_to_edge_of_collection_zone - QPointF( 0.000, -1.308), // + 50 cm distance to rover - QPointF( 1.308, 0.000), // + 30 cm distance_from_center_of_rover_to_edge_of_rover - QPointF( 0.000, 1.308), // 1.308m = 0.508m + 0.5m + 0.3m - - /* corner rovers: Northeast, Southwest */ - QPointF( 1.072, 1.072), // 1.072 = diagonal_distance_from_center_to_edge_of_collection_zone - QPointF(-1.072, -1.072) // + diagonal_distance_to_move_50cm - }; // + diagonal_distance_to_move_30cm - // 1.072m = 0.508 + 0.354 + 0.212 - - /* In this case, the yaw is the value that turns rover "left" and "right" */ - float rover_yaw[6] = - { - 0.000, // 0.00 * PI - 1.571, // 0.50 * PI - -3.142, // -1.00 * PI - -1.571, // -0.50 * PI - -2.356, // -0.75 * PI - 0.785 // 0.25 * PI - }; - - // Add rovers to the simulation and start the associated ROS nodes - for (int i = 0; i < n_rovers; i++) - { - emit sendInfoLogMessage("Adding rover "+rovers[i]+"..."); - return_msg = sim_mgr.addRover(rovers[i], rover_positions[i].x(), rover_positions[i].y(), 0, 0, 0, rover_yaw[i]); - emit sendInfoLogMessage(return_msg); - - emit sendInfoLogMessage("Starting rover node for "+rovers[i]+"..."); - return_msg = sim_mgr.startRoverNode(rovers[i]); - emit sendInfoLogMessage(return_msg); + progress_dialog.setValue((++n_rovers_created)*100.0f/n_rovers); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - progress_dialog.setValue((++n_rovers_created)*100.0f/n_rovers); - qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - - if(i == 0) - { - sleep(rover_load_delay); // Gives plugins enough time to finish loading + if(i == 0) + { + sleep(rover_load_delay); // Gives plugins enough time to finish loading + } } } + else + { + emit sendInfoLogMessage("Not creating rovers..."); + } - if (ui.powerlaw_distribution_radio_button->isChecked()) - { + if (ui.powerlaw_distribution_radio_button->isChecked()) + { emit sendInfoLogMessage("Adding powerlaw distribution of targets..."); return_msg = addPowerLawTargets(); emit sendInfoLogMessage(return_msg); - } - else if (ui.uniform_distribution_radio_button->isChecked()) - { + } + else if (ui.uniform_distribution_radio_button->isChecked()) + { emit sendInfoLogMessage("Adding uniform distribution of targets..."); return_msg = addUniformTargets(); emit sendInfoLogMessage(return_msg); - } - else if (ui.clustered_distribution_radio_button->isChecked()) - { + } + else if (ui.clustered_distribution_radio_button->isChecked()) + { emit sendInfoLogMessage("Adding clustered distribution of targets..."); return_msg = addClusteredTargets(); emit sendInfoLogMessage(return_msg); - } + } - // add walls given nw corner (x,y) and height and width (in meters) + // add walls given nw corner (x,y) and height and width (in meters) - //addWalls(-arena_dim/2, -arena_dim/2, arena_dim, arena_dim); + //addWalls(-arena_dim/2, -arena_dim/2, arena_dim, arena_dim); - // // Test rover movement - // displayLogMessage("Moving aeneas"); - // return_msg = sim_mgr.moveRover("aeneas", 10, 0, 0); - // displayLogMessage(return_msg); + // // Test rover movement + // displayLogMessage("Moving aeneas"); + // return_msg = sim_mgr.moveRover("aeneas", 10, 0, 0); + // displayLogMessage(return_msg); - //displayLogMessage("Starting the gazebo client to visualize the simulation."); - //sim_mgr.startGazeboClient(); + //displayLogMessage("Starting the gazebo client to visualize the simulation."); + //sim_mgr.startGazeboClient(); - ui.visualize_simulation_button->setEnabled(true); - ui.clear_simulation_button->setEnabled(true); + ui.visualize_simulation_button->setEnabled(true); + ui.clear_simulation_button->setEnabled(true); - ui.visualize_simulation_button->setStyleSheet("color: white;border:1px solid white;"); - ui.clear_simulation_button->setStyleSheet("color: white;border:1px solid white;"); + ui.visualize_simulation_button->setStyleSheet("color: white;border:1px solid white;"); + ui.clear_simulation_button->setStyleSheet("color: white;border:1px solid white;"); - ui.simulation_timer_combo_box->setEnabled(true); - ui.simulation_timer_combo_box->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); + ui.simulation_timer_combobox->setEnabled(true); + ui.simulation_timer_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); - emit sendInfoLogMessage("Finished building simulation."); + emit sendInfoLogMessage("Finished building simulation."); - // Visualize the simulation by default call button event handler - visualizeSimulationButtonEventHandler(); + if (ui.start_visualization_on_build_checkbox->isChecked()) + { + // Visualize the simulation by default call button event handler + visualizeSimulationButtonEventHandler(); + display_sim_visualization = true; + } + else + { + display_sim_visualization = false; + } } void RoverGUIPlugin::clearSimulationButtonEventHandler() @@ -1873,11 +2008,11 @@ void RoverGUIPlugin::clearSimulationButtonEventHandler() obstacle_call_count = 0; emit updateObstacleCallCount("0"); emit updateNumberOfTagsCollected("0"); - emit updateNumberOfSatellites("Number of GPS Satellites: ---"); + emit updateNumberOfSatellites("---"); // reset the simulation timer variables - ui.simulation_timer_combo_box->setEnabled(true); - ui.simulation_timer_combo_box->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); + ui.simulation_timer_combobox->setEnabled(true); + ui.simulation_timer_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px"); ui.simulationTimerStartLabel->setText("---"); ui.simulationTimerStopLabel->setText("---"); ui.currentSimulationTimeLabel->setText("---"); @@ -1961,8 +2096,10 @@ QString RoverGUIPlugin::stopROSJoyNode() QString RoverGUIPlugin::addUniformTargets() { + QString number_of_tags = ui.number_of_tags_combobox->currentText(); + QProgressDialog progress_dialog; - progress_dialog.setWindowTitle("Placing 256 Targets"); + progress_dialog.setWindowTitle("Placing " + number_of_tags + " Targets"); progress_dialog.setCancelButton(NULL); // no cancel button progress_dialog.setWindowModality(Qt::ApplicationModal); progress_dialog.resize(500, 50); @@ -1974,8 +2111,6 @@ QString RoverGUIPlugin::addUniformTargets() float proposed_x; float proposed_y; - // 256 piles of 1 tag - // d is the distance from the center of the arena to the boundary minus the barrier clearance, i.e. the region where tags can be placed // is d - U(0,2d) where U(a,b) is a uniform distribition bounded by a and b. // (before checking for collisions including the collection disk at the center) @@ -1984,7 +2119,7 @@ QString RoverGUIPlugin::addUniformTargets() progress_dialog.setValue(0.0); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - for (int i = 0; i < 256; i++) + for (int i = 0; i < number_of_tags.toInt(); i++) { do { @@ -1996,19 +2131,53 @@ QString RoverGUIPlugin::addUniformTargets() emit sendInfoLogMessage("Succeeded."); output = sim_mgr.addModel(QString("at")+QString::number(0), QString("at")+QString::number(i), proposed_x, proposed_y, 0, target_cluster_size_1_clearance); - progress_dialog.setValue(i*100.0f/256); + progress_dialog.setValue(i*100.0f/number_of_tags.toInt()); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); } - emit sendInfoLogMessage("Placed 256 single targets"); + emit sendInfoLogMessage("Placed " + number_of_tags + " single targets"); return output; } QString RoverGUIPlugin::addClusteredTargets() { + QString number_of_tags = ui.number_of_tags_combobox->currentText(); + int cluster_length = 0; + int cluster_width = 0; + + switch(number_of_tags.toInt()) + { + case 256: + cluster_length = 8; + cluster_width = 8; + break; + case 128: + cluster_length = 8; + cluster_width = 4; + break; + case 64: + cluster_length = 4; + cluster_width = 4; + break; + case 32: + cluster_length = 4; + cluster_width = 2; + break; + case 16: + cluster_length = 2; + cluster_width = 2; + break; + case 0: + cluster_length = 0; + cluster_width = 0; + default: + cluster_length = 1; + cluster_width = 1; + } + QProgressDialog progress_dialog; - progress_dialog.setWindowTitle("Placing 256 Targets into 4 Clusters (64 targets each)"); + progress_dialog.setWindowTitle("Placing " + number_of_tags + " Targets into four " + QString::number(cluster_length) + " x " + QString::number(cluster_width) + " clusters"); progress_dialog.setCancelButton(NULL); // no cancel button progress_dialog.setWindowModality(Qt::ApplicationModal); progress_dialog.setWindowFlags(progress_dialog.windowFlags() | Qt::WindowStaysOnTopHint); @@ -2020,13 +2189,14 @@ QString RoverGUIPlugin::addClusteredTargets() float proposed_x, proposed_x2; float proposed_y, proposed_y2; - float d = arena_dim/2.0-(barrier_clearance+target_cluster_size_64_clearance); + float target_cluster_clearance = target_cluster_size_1_clearance * ((cluster_length > cluster_width) ? (cluster_length) : (cluster_width)); + float d = arena_dim/2.0-(barrier_clearance+target_cluster_clearance); int cube_index = 0; progress_dialog.setValue(0.0); qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - // Four piles of 64 + // Four piles for (int i = 0; i < 4; i++) { do @@ -2035,14 +2205,14 @@ QString RoverGUIPlugin::addClusteredTargets() proposed_x = d - ((float) rand()) / RAND_MAX*2*d; proposed_y = d - ((float) rand()) / RAND_MAX*2*d; } - while (sim_mgr.isLocationOccupied(proposed_x, proposed_y, target_cluster_size_64_clearance)); + while (sim_mgr.isLocationOccupied(proposed_x, proposed_y, target_cluster_clearance)); - proposed_y2 = proposed_y - (target_cluster_size_1_clearance * 8); + proposed_y2 = proposed_y - (target_cluster_size_1_clearance * cluster_length); - for(int j = 0; j < 8; j++) { - proposed_x2 = proposed_x - (target_cluster_size_1_clearance * 8); + for(int j = 0; j < cluster_length; j++) { + proposed_x2 = proposed_x - (target_cluster_size_1_clearance * cluster_width); - for(int k = 0; k < 8; k++) { + for(int k = 0; k < cluster_width; k++) { output += sim_mgr.addModel(QString("at")+QString::number(0), QString("at")+QString::number(cube_index), proposed_x2, proposed_y2, 0, target_cluster_size_1_clearance); proposed_x2 += target_cluster_size_1_clearance; cube_index++; @@ -2056,7 +2226,7 @@ QString RoverGUIPlugin::addClusteredTargets() emit sendInfoLogMessage("Succeeded."); } - emit sendInfoLogMessage("Placed four clusters of 64 targets"); + emit sendInfoLogMessage("Placed four " + QString::number(cluster_length) + " x " + QString::number(cluster_width) + " clusters of targets"); return output; } @@ -2625,6 +2795,49 @@ void RoverGUIPlugin::overrideNumRoversCheckboxToggledEventHandler(bool checked) else ui.custom_num_rovers_combobox->setStyleSheet("color: grey; border:1px solid grey;"); } +void RoverGUIPlugin::createSavableWorldCheckboxToggledEventHandler(bool checked) +{ + ui.round_type_button_group->setEnabled(!checked); + ui.custom_num_rovers_combobox->setEnabled(!checked); + ui.override_num_rovers_checkbox->setEnabled(!checked); + ui.ground_texture_label->setEnabled(!checked); + ui.texture_combobox->setEnabled(!checked); + ui.simulation_timer_label->setEnabled(!checked); + ui.simulation_timer_combobox->setEnabled(!checked); + + ui.prelim_radio_button->click(); + unboundedRadioButtonEventHandler(false); + + // change specific GUI elements to the "disabled" color scheme + if(checked) + { + ui.round_type_button_group->setStyleSheet("color: grey;"); + ui.prelim_radio_button->setStyleSheet("color: grey;"); + ui.final_radio_button->setStyleSheet("color: grey;"); + ui.unbounded_radio_button->setStyleSheet("color: grey;"); + ui.custom_num_rovers_combobox->setStyleSheet("color: grey; border:1px solid grey; padding: 1px 0px 1px 3px;"); + ui.override_num_rovers_checkbox->setStyleSheet("clor: grey;"); + ui.ground_texture_label->setStyleSheet("color: grey;"); + ui.texture_combobox->setStyleSheet("color: grey; border:1px solid grey; padding: 1px 0px 1px 3px;"); + ui.simulation_timer_label->setStyleSheet("color: grey;"); + ui.simulation_timer_combobox->setStyleSheet("color: grey; border:1px solid grey; padding: 1px 0px 1px 3px;"); + } + // change specific GUI elements to the "enabled" color scheme + else + { + ui.round_type_button_group->setStyleSheet("color: white;"); + ui.prelim_radio_button->setStyleSheet("color: white;"); + ui.final_radio_button->setStyleSheet("color: white;"); + ui.unbounded_radio_button->setStyleSheet("color: white;"); + ui.custom_num_rovers_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px;"); + ui.override_num_rovers_checkbox->setStyleSheet("color: white;"); + ui.ground_texture_label->setStyleSheet("color: white"); + ui.texture_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px;"); + ui.simulation_timer_label->setStyleSheet("color: white;"); + ui.simulation_timer_combobox->setStyleSheet("color: white; border:1px solid white; padding: 1px 0px 1px 3px;"); + } +} + // Slot used to update the GUI diagnostic data output. Ensures we update from the correct process. void RoverGUIPlugin::receiveDiagsDataUpdate(QString rover_name, QString text, QColor colour) { diff --git a/src/rqt_rover_gui/src/rover_gui_plugin.h b/src/rqt_rover_gui/src/rover_gui_plugin.h index 36cadf32..c1bf9033 100644 --- a/src/rqt_rover_gui/src/rover_gui_plugin.h +++ b/src/rqt_rover_gui/src/rover_gui_plugin.h @@ -173,7 +173,10 @@ namespace rqt_rover_gui { void GPSCheckboxToggledEventHandler(bool checked); void EKFCheckboxToggledEventHandler(bool checked); void encoderCheckboxToggledEventHandler(bool checked); + void globalOffsetCheckboxToggledEventHandler(bool checked); + void uniqueRoverColorsCheckboxToggledEventHandler(bool checked); void overrideNumRoversCheckboxToggledEventHandler(bool checked); + void createSavableWorldCheckboxToggledEventHandler(bool checked); void mapSelectionListItemChangedHandler(QListWidgetItem* changed_item); void mapAutoRadioButtonEventHandler(bool marked); @@ -186,6 +189,8 @@ namespace rqt_rover_gui { void allStopButtonEventHandler(); void customWorldButtonEventHandler(); void customWorldRadioButtonEventHandler(bool marked); + void powerlawDistributionRadioButtonEventHandler(bool marked); + void unboundedRadioButtonEventHandler(bool marked); void buildSimulationButtonEventHandler(); void clearSimulationButtonEventHandler(); @@ -260,7 +265,7 @@ namespace rqt_rover_gui { bool display_sim_visualization; - // Object clearance. These values are used to quickly determine where objects can be placed int time simulation + // Object clearance. These values are used to quickly determine where objects can be placed in the simulation float target_cluster_size_64_clearance; float target_cluster_size_16_clearance; float target_cluster_size_4_clearance; diff --git a/src/rqt_rover_gui/src/rover_gui_plugin.ui b/src/rqt_rover_gui/src/rover_gui_plugin.ui index 8b4dcdc5..65753373 100644 --- a/src/rqt_rover_gui/src/rover_gui_plugin.ui +++ b/src/rqt_rover_gui/src/rover_gui_plugin.ui @@ -41,7 +41,7 @@ border-color: rgb(255, 255, 255); 330 10 761 - 551 + 521 @@ -118,10 +118,10 @@ QTabBar::tab:only-one { - 350 - 290 - 281 - 191 + 246 + 306 + 209 + 179 @@ -140,10 +140,10 @@ QTabBar::tab:only-one { - 350 - 10 - 320 - 271 + 392 + 26 + 354 + 249 @@ -162,10 +162,10 @@ QTabBar::tab:only-one { - 50 - 290 - 281 - 191 + 16 + 306 + 209 + 179 @@ -178,10 +178,10 @@ QTabBar::tab:only-one { - 10 - 10 - 320 - 271 + 16 + 26 + 354 + 249 @@ -191,144 +191,425 @@ QTabBar::tab:only-one { QFrame::Raised - + - 670 - 50 - 81 - 22 + 470 + 300 + 281 + 191 - - <html><head/><body><p>GPS aligned with the map output (mutually recursive with MAP)</p></body></html> + + QFrame::StyledPanel + + + QFrame::Raised + + + + true + + + + 200 + 145 + 60 + 25 + + + + color: rgb(255, 255, 255); +border-color: rgb(255, 255, 255); +border: 1px solid white; + + + + Popout + + + + + + 30 + 40 + 60 + 22 + + + + <html><head/><body><p>EKF combination of IMU, Encoders and GPS (mutually recursive with NAVSAT)</p></body></html> + + + color: rgb(255, 255, 255); + + + MAP + + + true + + + + + + 130 + 40 + 75 + 22 + + + + <html><head/><body><p>EKF combination of IMU and Encoders</p></body></html> + + + color: rgb(255, 255, 255); + + + ODOM + + + false + + + + + + 30 + 60 + 91 + 22 + + + + <html><head/><body><p>GPS aligned with the map output (mutually recursive with MAP)</p></body></html> + + + color: rgb(255, 255, 255); + + + NAVSAT + + + false + + + + + true + + + + 30 + 110 + 81 + 20 + + + + color: rgb(255, 255, 255); + + + Manual + + + false + + + + + true + + + + 130 + 110 + 61 + 20 + + + + color: rgb(255, 255, 255); + + + Auto + + + true + + + + + + 20 + 145 + 165 + 25 + + + + color: rgb(255, 255, 255); + + + Unique Rover Colors + + + + + + 130 + 60 + 121 + 25 + + + + color: rgb(255, 255, 255); + + + Global Frame + + + + + + 10 + 20 + 125 + 20 + + + + color: rgb(255, 255, 255); + + + Frame Views + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + 10 + 90 + 90 + 20 + + + + color: rgb(255, 255, 255); + + + Panning + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + 490 + 290 + 105 + 20 + - color: rgb(255, 255, 255); + color: white; +border: 1px solid white; +padding: 1px; - NAVSAT + Map Settings - - false + + Qt::AlignCenter + + + true - + - 670 - 10 - 91 - 22 + 240 + 300 + 221 + 191 - - <html><head/><body><p>EKF combination of IMU, Encoders and GPS (mutually recursive with NAVSAT)</p></body></html> + + QFrame::StyledPanel - - color: rgb(255, 255, 255); + + QFrame::Raised - - MAP + + + + + 10 + 300 + 221 + 191 + - - true + + QFrame::StyledPanel + + + QFrame::Raised - + - 670 - 30 - 81 - 22 + 260 + 290 + 40 + 20 - - <html><head/><body><p>EKF combination of IMU and Encoders</p></body></html> - - color: rgb(255, 255, 255); + color: white; +border: 1px solid white; +padding: 1px; - ODOM + IMU - - false + + Qt::AlignCenter - - - + true + + - 670 - 85 - 117 + 30 + 290 + 90 20 - color: rgb(255, 255, 255); + color: white; +border: 1px solid white; +padding: 1px; - Manual + Ultrasound - - false + + Qt::AlignCenter - - map_display_button_group - - - - true + + + + 10 + 20 + 366 + 261 + + + + QFrame::StyledPanel + + QFrame::Raised + + + - 670 - 110 - 171 - 16 + 386 + 20 + 366 + 261 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + 406 + 10 + 40 + 20 - color: rgb(255, 255, 255); + color: white; +border: 1px solid white; +padding: 1px; - Auto + Map - - true + + Qt::AlignCenter - - map_display_button_group - - - - + true + + - 680 - 140 - 61 - 22 + 30 + 10 + 65 + 20 - color: rgb(255, 255, 255); -border-color: rgb(255, 255, 255); -border: 1px solid white; - + color: white; +border: 1px solid white; +padding: 1px; - Popout + Camera + + + Qt::AlignCenter + + + true + map_frame_frame + camera_frame_frame + us_frame_frame + imu_frame_frame + map_settings_frame + imu_frame + map_frame + us_frame + camera_frame + map_settings_label + map_label_2 + map_label + ultrasound_label + IMU_label @@ -338,9 +619,9 @@ border: 1px solid white; 10 - 60 - 301 - 306 + 20 + 531 + 311 @@ -353,9 +634,9 @@ border: 1px solid white; 10 - 10 - 141 - 161 + 20 + 161 + 111 @@ -371,10 +652,10 @@ border-color: rgb(255, 255, 255); - 30 + 20 30 91 - 22 + 16 @@ -393,10 +674,10 @@ border-color: rgb(255, 255, 255); - 30 - 90 + 20 + 70 101 - 22 + 16 @@ -412,10 +693,10 @@ border-color: rgb(255, 255, 255); - 30 - 60 - 91 - 22 + 20 + 50 + 101 + 16 @@ -434,10 +715,10 @@ border-color: rgb(255, 255, 255); - 30 - 120 - 117 - 22 + 20 + 90 + 121 + 16 @@ -447,7 +728,7 @@ border-color: rgb(255, 255, 255); color: rgb(255, 255, 255); - Custom + Custom World true @@ -460,8 +741,8 @@ border-color: rgb(255, 255, 255); - 140 - 130 + 160 + 105 70 25 @@ -482,10 +763,10 @@ border: 1px solid white; - 160 - 30 - 121 - 91 + 280 + 120 + 211 + 131 @@ -495,7 +776,7 @@ border-color: rgb(255, 255, 255); Round Type - + true @@ -503,7 +784,7 @@ border-color: rgb(255, 255, 255); 10 30 - 161 + 111 22 @@ -523,25 +804,120 @@ border-color: rgb(255, 255, 255); - 10 - 60 - 117 - 22 + 10 + 50 + 71 + 22 + + + + color: rgb(255, 255, 255); + + + Final + + + + + true + + + + 10 + 70 + 111 + 22 + + + + color: rgb(255, 255, 255); + + + Unbounded + + + + + + 40 + 98 + 81 + 20 + + + + color: grey; + + + <html><head/><body><p align="center">Arena Size</p></body></html> + + + + + false + + + + 125 + 95 + 71 + 27 - color: rgb(255, 255, 255); - - - Final + color: grey; +border-color: grey; +border: 1px solid grey; +padding: 1px 0px 1px 3px; /*This makes text colour work*/ + + + + 15 + + + + + 20 + + + + + 25 + + + + + 30 + + + + + 35 + + + + + 40 + + + + + 45 + + + + + 50 + + - + 20 - 190 + 180 111 20 @@ -559,9 +935,9 @@ border-color: rgb(255, 255, 255); - 150 - 190 - 131 + 140 + 180 + 121 27 @@ -591,14 +967,16 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ - 68 - 162 - 200 + 58 + 140 + 203 20 - color: rgb(255, 255, 255); + color: white; +border: 1px solid white; +padding: 1px; @@ -611,7 +989,7 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ 20 - 230 + 220 181 22 @@ -632,9 +1010,9 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ - 210 - 230 - 71 + 200 + 220 + 61 27 @@ -680,17 +1058,27 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ 6 + + + 7 + + + + + 8 + + - + true 150 - 270 - 131 - 23 + 260 + 111 + 27 @@ -728,6 +1116,11 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ 10 min (Testing) + + + 20 min (Preliminary) + + 30 min (Preliminary) @@ -743,7 +1136,7 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ 20 - 270 + 260 130 20 @@ -758,62 +1151,217 @@ padding: 1px 0px 1px 3px; /*This makes text colour work*/ Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + true + + + + 280 + 260 + 211 + 22 + + + + + 0 + 0 + + + + + 16777215 + 22 + + + + + 10 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When checked, a Gazebo world without rovers, walls, ground texture, or a collection zone will be created. The purpose of this option is to generate tag distributions using the Uniform, Clustered, or Power Law in a way that you can save the world file from Gazebo and re-use that same distribution later using the Custom world option. It will also load much faster as well when loading a pre-built distribution.</p></body></html> + + + <html><head/><body><p>When checked, a Gazebo world without rovers, walls, ground texture, or a collection zone will be created. The purpose of this option is to generate tag distributions using the Uniform, Clustered, or Power Law in a way that you can save the world file from Gazebo and re-use that same distribution later using the Custom world option. It will also load much faster as well when loading a pre-built distribution.</p></body></html> + + + color: rgb(255, 255, 255); + + + Create Savable Gazebo World + + + false + + + + + false + + + + 280 + 55 + 131 + 27 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The number of april tag cubes generated by the Uniform or Clustered distributions.</p></body></html> + + + <html><head/><body><p>The number of april tag cubes generated by the Uniform or Clustered distributions.</p></body></html> + + + color: grey; +border-color: grey; +border: 1px solid grey; +padding: 1px 0px 1px 3px; /*This makes text colour work*/ + + + + + 256 + + + + + 128 + + + + + 64 + + + + + 32 + + + + + 16 + + + + + 0 + + + + + + + 280 + 35 + 121 + 20 + + + + color: grey; + + + <html><head/><body><p align="center">Number of Cubes</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 280 + 80 + 231 + 20 + + + + color: rgb(255, 255, 255); + + + <html><head/><body><p align="center"><span style=" font-size:8pt;">*not available for Power Law or Custom World</span></p></body></html> + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + round_type_button_group + target_distribution_group_box + custom_world_path_button + ground_texture_label + texture_combobox + custom_world_path + override_num_rovers_checkbox + custom_num_rovers_combobox + simulation_timer_combobox + simulation_timer_label + create_savable_world_checkbox + number_of_tags_label + number_of_tags_label_2 + number_of_tags_combobox - 80 - 50 - 121 + 205 + 10 + 140 20 - - <html><head/><body><p><span style=" color:#ffffff;">Simulation Setup</span></p></body></html> - - - - - - 290 - 20 - 501 - 427 - + + color: white; +border: 1px solid white; +padding: 1px; - + <html><head/><body><p><span style=" color:#ffffff;">Simulation Setup</span></p></body></html> - - ../resources/rover.png + + Qt::AlignCenter - + - 80 - 370 - 161 - 27 + 220 + 340 + 40 + 20 - color: rgb(255, 255, 255); -border-color: rgb(255, 255, 255); -border: 1px solid white; - + color: white; +border: 1px solid white; +padding: 1px; - Build Simulation + GPS + + + Qt::AlignCenter - + - 510 - 330 - 191 - 161 + 200 + 350 + 201 + 141 @@ -822,111 +1370,272 @@ border: 1px solid white; QFrame::Raised - + + + + 10 + 25 + 61 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Ref. Lat. + + + + + + 10 + 10 + 61 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Rate + + + + + + 10 + 40 + 61 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Ref. Long. + + + + + + 10 + 55 + 61 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Ref. Head. + + + + + + 79 + 10 + 111 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + val + + + + + + 79 + 25 + 111 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + val + + + - 10 - 10 - 71 - 17 + 79 + 40 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); - Horz. Res + val - + - 10 - 70 - 71 - 17 + 79 + 55 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); - Min Ang. + val - + 10 - 90 - 71 - 17 + 85 + 61 + 16 + + + 10 + + color: rgb(255, 255, 255); - Max Ang. + Drift - + 10 - 50 - 71 - 17 + 100 + 61 + 16 + + + 10 + + color: rgb(255, 255, 255); - Max + Drift Freq. - + 10 - 30 - 71 - 17 + 115 + 61 + 16 + + + 10 + + color: rgb(255, 255, 255); - Min + Noise - + - 10 - 110 - 131 - 17 + 79 + 85 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); - Range Resolution + val - + - 140 - 110 - 41 - 17 + 79 + 100 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -934,15 +1643,20 @@ border: 1px solid white; val - + - 140 - 90 - 41 - 17 + 79 + 115 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -950,31 +1664,41 @@ border: 1px solid white; val - + - 140 + 10 70 - 41 - 17 + 61 + 16 + + + 10 + + color: rgb(255, 255, 255); - val + Ref. Alt. - + - 140 - 50 - 41 - 17 + 79 + 70 + 111 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -982,213 +1706,288 @@ border: 1px solid white; val - + + + + + 410 + 350 + 341 + 141 + + + + QFrame::StyledPanel + + + QFrame::Raised + + - 140 - 30 - 41 - 17 + 170 + 10 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - val + Rate - + - 140 - 10 - 41 - 17 + 10 + 25 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - val + Drift - + 10 - 130 - 121 - 17 + 40 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - Gaussian Noise + Noise - + - 140 - 130 - 41 - 17 + 10 + 75 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - val + Offsets - - - - true - - - - 80 - 400 - 161 - 27 - - - - color: rgb(255, 255, 255); -border-color: rgb(255, 255, 255); -border: 1px solid white; - - - - End Simulation - - - - - - 360 - 310 - 31 - 17 - - - - color: rgb(255, 255, 255); - - - GPS - - - - - - 350 - 320 - 151 - 181 - - - - QFrame::StyledPanel - - - QFrame::Raised - - + - 10 - 30 - 61 - 17 + 170 + 25 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - Ref. Lat. + Drift - + + + + 170 + 40 + 60 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Noise + + + 10 10 - 61 - 17 + 60 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Accel. + + + + + + 170 + 75 + 60 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + Drift + + + + + + 170 + 90 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - Rate + Noise - + - 10 - 50 - 71 - 17 + 170 + 60 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - Ref. Long. + Heading - + 10 - 70 - 71 - 17 + 60 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - Ref. Head. + RPY - + - 90 - 10 - 51 - 17 + 10 + 95 + 60 + 16 + + + 10 + + color: rgb(255, 255, 255); - val + Noise - + - 90 - 30 - 51 - 17 + 240 + 10 + 90 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1196,15 +1995,20 @@ border: 1px solid white; val - + - 90 - 50 - 51 - 17 + 240 + 25 + 90 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1212,15 +2016,20 @@ border: 1px solid white; val - + - 90 - 70 - 51 - 17 + 240 + 40 + 90 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1228,63 +2037,83 @@ border: 1px solid white; val - + - 10 - 110 - 71 - 17 + 240 + 75 + 90 + 16 + + + 10 + + color: rgb(255, 255, 255); - Drift + val - + - 10 - 130 - 71 - 17 + 240 + 90 + 90 + 16 + + + 10 + + color: rgb(255, 255, 255); - Drift Freq. + val - + - 10 - 150 - 71 - 17 + 80 + 25 + 85 + 16 + + + 10 + + color: rgb(255, 255, 255); - Noise + val - + - 90 - 110 - 51 - 17 + 80 + 40 + 85 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1292,15 +2121,20 @@ border: 1px solid white; val - + - 90 - 130 - 51 - 17 + 80 + 75 + 85 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1308,15 +2142,20 @@ border: 1px solid white; val - + - 90 - 150 - 51 - 17 + 80 + 95 + 85 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1324,31 +2163,44 @@ border: 1px solid white; val - + 10 - 90 - 71 - 17 + 110 + 60 + 16 + + + 10 + + + + <html><head/><body><p>Magnetic Declination</p></body></html> + color: rgb(255, 255, 255); - Ref. Alt. + Mag. Dec. - + - 90 - 90 - 51 - 17 + 80 + 110 + 85 + 16 + + + 10 + + color: rgb(255, 255, 255); @@ -1357,29 +2209,13 @@ border: 1px solid white; - - - - 360 - 130 - 31 - 17 - - - - color: rgb(255, 255, 255); - - - IMU - - - + - 350 - 140 - 271 - 171 + 560 + 20 + 191 + 131 @@ -1388,15 +2224,20 @@ border: 1px solid white; QFrame::Raised - + - 130 - 10 + 10 + 15 61 17 + + + 10 + + color: rgb(255, 255, 255); @@ -1404,23 +2245,28 @@ border: 1px solid white; Rate - + 10 - 30 - 91 + 35 + 61 17 + + + 10 + + color: rgb(255, 255, 255); - Drift + Width - + 10 @@ -1429,182 +2275,158 @@ border: 1px solid white; 17 + + + 10 + + color: rgb(255, 255, 255); - Noise + Height - + 10 - 100 - 81 + 65 + 61 17 - - color: rgb(255, 255, 255); - - - Offsets - - - - - - 130 - 30 - 91 - 17 - + + + 10 + color: rgb(255, 255, 255); - Drift + Format - + - 130 - 50 - 91 + 120 + 15 + 60 17 - - color: rgb(255, 255, 255); - - - Noise - - - - - - 10 - 10 - 61 - 17 - + + + 10 + color: rgb(255, 255, 255); - Accel. + val - + - 130 - 100 - 91 + 120 + 35 + 60 17 - - color: rgb(255, 255, 255); - - - Drift - - - - - - 130 - 120 - 91 - 17 - + + + 10 + color: rgb(255, 255, 255); - Noise + val - + - 130 - 80 - 91 + 120 + 50 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - Heading + val - + - 10 - 80 - 81 + 120 + 65 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - RPY + val - + 10 - 130 + 85 81 17 - - color: rgb(255, 255, 255); - - - Noise - - - - - - 180 - 10 - 41 - 17 - + + + 10 + color: rgb(255, 255, 255); - val + Noise Mean - + - 220 - 30 - 41 + 120 + 85 + 60 17 + + + 10 + + color: rgb(255, 255, 255); @@ -1612,31 +2434,41 @@ border: 1px solid white; val - + - 220 - 50 + 47 + 100 41 17 + + + 10 + + color: rgb(255, 255, 255); - val + Stdev - + - 220 + 120 100 - 41 + 60 17 + + + 10 + + color: rgb(255, 255, 255); @@ -1644,111 +2476,174 @@ border: 1px solid white; val - + label_19 + label_20 + label_21 + label_18 + camera_update_rate + camera_width + camera_height + camera_format + label_25 + camera_noise_mean + label_45 + camera_noise_stdev + + + + + 560 + 170 + 191 + 161 + + + + QFrame::StyledPanel + + + QFrame::Raised + + - 180 - 120 - 41 + 10 + 10 + 71 17 + + + 10 + + color: rgb(255, 255, 255); - val + Horz. Res - + - 60 - 30 - 41 - 16 + 10 + 70 + 71 + 17 + + + 10 + + color: rgb(255, 255, 255); - val + Min Ang. - + - 60 - 50 - 41 - 16 + 10 + 90 + 71 + 17 + + + 10 + + color: rgb(255, 255, 255); - val + Max Ang. - + - 70 - 100 - 41 + 10 + 50 + 71 17 + + + 10 + + color: rgb(255, 255, 255); - val + Max - + - 70 - 130 - 51 + 10 + 30 + 71 17 + + + 10 + + color: rgb(255, 255, 255); - val + Min - + - 20 - 150 - 151 + 10 + 110 + 131 17 + + + 10 + + color: rgb(255, 255, 255); - Magnetic Declination + Range Resolution - + - 180 - 150 - 51 + 120 + 110 + 60 17 + + + 10 + + color: rgb(255, 255, 255); @@ -1756,111 +2651,104 @@ border: 1px solid white; val - - - - - 520 - 0 - 51 - 17 - - - - color: rgb(255, 255, 255); - - - Camera - - - - - - 510 - 10 - 151 - 131 - - - - QFrame::StyledPanel - - - QFrame::Raised - - + - 10 - 10 - 61 + 120 + 90 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - Rate + val - + - 10 - 30 - 61 + 120 + 70 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - Width + val - + - 10 + 120 50 - 61 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - Height + val - + - 10 - 70 - 61 + 120 + 30 + 60 17 + + + 10 + + color: rgb(255, 255, 255); - Format + val - + - 80 + 120 10 - 51 + 60 17 + + + 10 + + color: rgb(255, 255, 255); @@ -1868,407 +2756,271 @@ border: 1px solid white; val - + - 80 - 30 - 51 + 10 + 130 + 121 17 + + + 10 + + color: rgb(255, 255, 255); - val + Gaussian Noise - + - 80 - 50 - 51 + 120 + 130 + 60 17 + + + 10 + + color: rgb(255, 255, 255); val - - + + + + + + 580 + 160 + 90 + 20 + + + + color: white; +border: 1px solid white; +padding: 1px; + + + Ultrasound + + + Qt::AlignCenter + + + + + + 430 + 340 + 40 + 20 + + + + color: white; +border: 1px solid white; +padding: 1px; + + + IMU + + + Qt::AlignCenter + + + + + + 580 + 10 + 65 + 20 + + + + color: white; +border: 1px solid white; +padding: 1px; + + + Camera + + + Qt::AlignCenter + + + + + + 10 + 350 + 181 + 141 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + true + - 80 - 70 - 51 - 17 + 30 + 105 + 21 + 22 + + + 0 + 0 + + + + + 16777215 + 22 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When checked, a Gazebo world without rovers, walls, ground texture, or a collection zone will be created. The purpose of this option is to generate tag distributions using the Uniform, Clustered, or Power Law in a way that you can save the world file from Gazebo and re-use that same distribution later using the Custom world option. It will also load much faster as well when loading a pre-built distribution.</p></body></html> + + + + color: rgb(255, 255, 255); - val + + + + true - + - 10 - 90 - 81 - 17 + 55 + 100 + 91 + 31 color: rgb(255, 255, 255); - Noise Mean + <html><head/><body><p align="center"><span style=" font-size:8pt;">Start Visualization On Build</span></p></body></html> + + + Qt::AlignCenter + + + true + + + 0 - + - 100 - 90 - 41 - 17 + 10 + 10 + 161 + 27 - color: rgb(255, 255, 255); + color: rgb(255, 255, 255); +border-color: rgb(255, 255, 255); +border: 1px solid white; + - val + Build Simulation - + + + true + - 50 - 110 - 41 - 17 + 10 + 40 + 161 + 27 - color: rgb(255, 255, 255); + color: rgb(255, 255, 255); +border-color: rgb(255, 255, 255); +border: 1px solid white; + - Stdev + End Simulation - + + + true + - 100 - 110 - 41 - 17 + 10 + 70 + 161 + 27 - color: rgb(255, 255, 255); + color: rgb(255, 255, 255); +border-color: rgb(255, 255, 255); +border: 1px solid white; + - val + Toggle Visualization - label_19 - label_20 - label_21 - label_18 - camera_update_rate - camera_width - camera_height - camera_format - label_25 - camera_noise_mean - label_45 - camera_noise_stdev - - - - true - - - - 80 - 430 - 161 - 27 - - - - color: rgb(255, 255, 255); -border-color: rgb(255, 255, 255); -border: 1px solid white; - - - - Toggle Visualization - - - - - - 520 - 320 - 81 - 17 - - - - color: rgb(255, 255, 255); - - - Ultrasound - - rover_image_label + button_frame setup_group label_7 - build_simulation_button - frame_2 - clear_simulation_button - frame_4 + GPS_frame label_11 - frame_5 + IMU_frame + camera_frame_status + ultrasound_frame + label_10 label_12 - frame_6 label_17 - visualize_simulation_button - label_10 - - - - Task Status - - - - - 100 - 60 - 201 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">Number of Targets Detected:</span></p></body></html> - - - - - - 310 - 60 - 67 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">0</span></p></body></html> - - - - - - 100 - 90 - 201 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">Number of Targets Collected:</span></p></body></html> - - - - - - 310 - 90 - 67 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">0</span></p></body></html> - - - - - - 100 - 150 - 181 - 17 - - - - <html><head/><body><p><span style=" color:#fefefe;">Obstacle Avoidance Calls:</span></p></body></html> - - - - - - 310 - 150 - 67 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">0</span></p></body></html> - - - - - - 210 - 250 - 250 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> - - - - - - 210 - 280 - 250 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> - - - - - - 210 - 310 - 250 - 17 - - - - <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> - - - - - - 100 - 250 - 100 - 17 - - - - <html><head/><body><p><span style=" color:#fefefe;">Current Time:</span></p></body></html> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 100 - 280 - 100 - 17 - - - - <html><head/><body><p><span style=" color:#fefefe;">Timer Start:</span></p></body></html> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 100 - 310 - 100 - 17 - - - - <html><head/><body><p><span style=" color:#fefefe;">Timer Stop:</span></p></body></html> - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - true - - - - 90 - 220 - 400 - 120 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - 100 - 210 - 310 - 25 - - - - color: white; -border: 1px solid white; -padding: 1px; - - - <html><head/><body><p><span style=" color:#fefefe;">Simulation Timer (for simulated rovers only)</span></p></body></html> - - - Qt::AlignCenter - - - Simulation_Timer_Frame - label_6 - num_targets_detected_label - label_8 - num_targets_collected_label - label_9 - perc_of_time_avoiding_obstacles - currentSimulationTimeLabel - simulationTimerStartLabel - simulationTimerStopLabel - currentSimulationTimeTitle - simulationTimerStartTitle - simulationTimerStopTitle - simulation_timer_frame_label @@ -2277,10 +3029,10 @@ padding: 1px; - 600 - 560 - 201 - 141 + 650 + 547 + 211 + 163 @@ -2292,10 +3044,10 @@ padding: 1px; - 10 + 24 10 - 181 - 121 + 161 + 141 @@ -2311,8 +3063,8 @@ padding: 1px; 10 - 40 - 171 + 50 + 121 30 @@ -2333,7 +3085,7 @@ padding: 1px; 10 - 25 + 30 117 20 @@ -2358,7 +3110,7 @@ padding: 1px; 10 - 95 + 110 150 22 @@ -2380,7 +3132,7 @@ border: 1px solid white; 10 - 70 + 85 150 22 @@ -2400,10 +3152,10 @@ border: 1px solid white; - 810 - 590 - 191 - 111 + 870 + 547 + 211 + 163 @@ -2415,8 +3167,8 @@ border: 1px solid white; - 110 - 40 + 118 + 70 41 16 @@ -2430,8 +3182,8 @@ border: 1px solid white; - 90 - 60 + 98 + 90 41 16 @@ -2445,8 +3197,8 @@ border: 1px solid white; - 130 - 60 + 138 + 90 41 16 @@ -2460,8 +3212,8 @@ border: 1px solid white; - 110 - 80 + 118 + 110 41 16 @@ -2475,8 +3227,8 @@ border: 1px solid white; - 30 - 40 + 24 + 70 41 16 @@ -2490,8 +3242,8 @@ border: 1px solid white; - 50 - 60 + 44 + 90 41 16 @@ -2505,8 +3257,8 @@ border: 1px solid white; - 10 - 60 + 5 + 90 41 16 @@ -2520,8 +3272,8 @@ border: 1px solid white; - 30 - 80 + 24 + 110 41 16 @@ -2535,10 +3287,10 @@ border: 1px solid white; - 120 - 10 - 67 - 17 + 128 + 30 + 51 + 20 @@ -2547,14 +3299,17 @@ border: 1px solid white; Drive + + Qt::AlignCenter + - 40 - 10 - 67 - 17 + 20 + 30 + 81 + 20 @@ -2563,6 +3318,9 @@ border: 1px solid white; Gripper + + Qt::AlignCenter + @@ -2630,26 +3388,13 @@ border: 1px solid white; <html><head/><body><p><span style=" color:#ffffff;">version</span></p></body></html> - - - - 10 - 330 - 191 - 20 - - - - <html><head/><body><p><span style=" color:#ffffff;">Not Connected</span></p></body></html> - - 10 - 510 - 571 - 211 + 520 + 631 + 201 @@ -2708,7 +3453,7 @@ QTabBar::tab:only-one { - 1 + 0 @@ -2719,8 +3464,8 @@ QTabBar::tab:only-one { 0 0 - 561 - 171 + 631 + 161 @@ -2734,8 +3479,8 @@ QTabBar::tab:only-one { 0 0 - 571 - 171 + 631 + 161 @@ -2840,25 +3585,381 @@ QTabBar::tab:only-one { <html><head/><body><p><span style=" font-size:9pt; color:#ffffff;">Map</span></p></body></html> - + + + true + 10 - 360 - 191 + 404 + 311 + 101 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 40 + 80 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#fefefe;">Current Time:</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 55 + 80 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#fefefe;">Timer Start:</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 70 + 80 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#fefefe;">Timer Stop:</span></p></body></html> + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 100 + 40 + 205 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> + + + + + + 100 + 55 + 205 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> + + + + + + 100 + 70 + 205 + 17 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">---</span></p></body></html> + + + + + + 10 + 20 + 181 + 16 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">Number of Targets Collected:</span></p></body></html> + + + + + + 192 + 20 + 110 + 15 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">0</span></p></body></html> + + + + + + + 29 + 394 + 271 20 - - true + + + 10 + - - <html><head/><body><p>Displays the number of GPS Satellites detected by the selected physical rover. Simulated rovers will not display a value here.</p></body></html> + + color: white; +border: 1px solid white; +padding: 1px; - <html><head/><body><p><span style=" color:#ffffff;"></span></p></body></html> + <html><head/><body><p><span style=" color:#fefefe;">Sim Timer And Status (simulated rovers only)</span></p></body></html> + + + Qt::AlignCenter + + + + + true + + + + 10 + 300 + 311 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 191 + 15 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">Not Connected</span></p></body></html> + + + + + + 170 + 30 + 120 + 16 + + + + + 10 + + + + true + + + <html><head/><body><p>Displays the number of GPS Satellites detected by the selected physical rover. Simulated rovers will not display a value here.</p></body></html> + + + color: rgb(255, 255, 255); + + + <html><head/><body><p>---</p></body></html> + + + + + + 10 + 50 + 150 + 16 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#fefefe;">Obstacle Avoidance Calls:</span></p></body></html> + + + + + + 170 + 50 + 120 + 16 + + + + + 10 + + + + <html><head/><body><p><span style=" color:#ffffff;">0</span></p></body></html> + + + + + + 10 + 30 + 150 + 16 + + + + + 10 + + + + color: rgb(255, 255, 255); + + + <html><head/><body><p>Number of GPS Satellites:</p></body></html> + + + + + + + 870 + 547 + 211 + 163 + + + + QFrame::StyledPanel + + QFrame::Raised + + + + + 20 + 55 + 171 + 51 + + + + + 12 + + + + <html><head/><body><p><span style=" color:#ffffff;">Autonomous Control Enabled</span></p></body></html> + + + Qt::AlignCenter + + + true + + + joystick_disabled_frame + joystick_frame + tab_widget + control_frame + label + label_2 + label_3 + label_4 + version_number_label + log_tab + Rover_frame + label_13 + map_list_label + Simulation_Timer_Frame + simulation_timer_frame_label + status_frame @@ -2897,6 +3998,5 @@ QTabBar::tab:only-one { -