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 { -