From bb46d70aa158e8200d837a5c6b746a07230b90ea Mon Sep 17 00:00:00 2001 From: Sanat Dhanyamraju Date: Sun, 13 Sep 2026 20:10:54 -0400 Subject: [PATCH 01/21] remove raw vision --- src/rj_common/include/rj_common/context.hpp | 1 - src/rj_common/src/logger.cpp | 6 --- src/rj_protos/protos/LogFrame.proto | 2 - src/rj_ui/CMakeLists.txt | 1 - src/rj_ui/include/rj_ui/field_view.hpp | 2 - src/rj_ui/include/rj_ui/log_viewer.hpp | 2 - src/rj_ui/include/rj_ui/main_window.hpp | 2 - src/rj_ui/include/rj_ui/processor.hpp | 2 - .../rj_ui/ros2_temp/raw_vision_packet_sub.hpp | 38 ------------------- src/rj_ui/qt/LogViewer.ui | 18 --------- src/rj_ui/qt/MainWindow.ui | 18 --------- src/rj_ui/src/field_view.cpp | 37 ------------------ src/rj_ui/src/log_viewer.cpp | 10 ----- src/rj_ui/src/main_window.cpp | 10 ----- src/rj_ui/src/processor.cpp | 4 -- .../src/ros2_temp/raw_vision_packet_sub.cpp | 19 ---------- 16 files changed, 172 deletions(-) delete mode 100644 src/rj_ui/include/rj_ui/ros2_temp/raw_vision_packet_sub.hpp delete mode 100644 src/rj_ui/src/ros2_temp/raw_vision_packet_sub.cpp diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 408e7b18ef7..426416089cd 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -98,7 +98,6 @@ struct Context { DebugDrawer debug_drawer; std::vector referee_packets; - std::vector raw_vision_packets; WorldState world_state; diff --git a/src/rj_common/src/logger.cpp b/src/rj_common/src/logger.cpp index a0530aa03e0..400e9aa58fa 100644 --- a/src/rj_common/src/logger.cpp +++ b/src/rj_common/src/logger.cpp @@ -149,12 +149,6 @@ std::shared_ptr Logger::create_log_frame(Context* context) { // Debug drawing context->debug_drawer.fill_log_frame(log_frame.get()); - // Copy raw vision packets. - for (const SSL_WrapperPacket& packet : context->raw_vision_packets) { - log_frame->add_raw_vision()->CopyFrom(packet); - } - context->raw_vision_packets.clear(); - // Copy referee packets. for (const auto& packet : context->referee_packets) { Referee* referee = log_frame->add_raw_refbox(); diff --git a/src/rj_protos/protos/LogFrame.proto b/src/rj_protos/protos/LogFrame.proto index 3cc895b065d..aa224e92e67 100644 --- a/src/rj_protos/protos/LogFrame.proto +++ b/src/rj_protos/protos/LogFrame.proto @@ -3,7 +3,6 @@ package Packet; import "referee.proto"; import "Point.proto"; -import "ssl_vision_wrapper.proto"; import "RadioTx.proto"; import "RadioRx.proto"; @@ -81,7 +80,6 @@ message LogFrame { optional LogConfig log_config = 2047; // Network packets received since the last iteration - repeated SSL_WrapperPacket raw_vision = 1; repeated Referee raw_refbox = 27; repeated RadioRx radio_rx = 3; diff --git a/src/rj_ui/CMakeLists.txt b/src/rj_ui/CMakeLists.txt index 3faf9900555..4593f283708 100644 --- a/src/rj_ui/CMakeLists.txt +++ b/src/rj_ui/CMakeLists.txt @@ -61,7 +61,6 @@ set(SRC_FILES src/ros2_temp/autonomy_interface.cpp src/ros2_temp/debug_draw_interface.cpp - src/ros2_temp/raw_vision_packet_sub.cpp src/ros2_temp/referee_sub.cpp src/ros2_temp/soccer_config_client.cpp diff --git a/src/rj_ui/include/rj_ui/field_view.hpp b/src/rj_ui/include/rj_ui/field_view.hpp index 7fdf91a1b38..ede381e27c6 100644 --- a/src/rj_ui/include/rj_ui/field_view.hpp +++ b/src/rj_ui/include/rj_ui/field_view.hpp @@ -62,8 +62,6 @@ class FieldView : public QWidget { // If false, it will draw a red border. bool live{}; - bool showRawRobots; - bool showRawBalls; bool showCoords; bool showDotPatterns; bool showTeamNames; diff --git a/src/rj_ui/include/rj_ui/log_viewer.hpp b/src/rj_ui/include/rj_ui/log_viewer.hpp index 82264da069c..8801ed50890 100644 --- a/src/rj_ui/include/rj_ui/log_viewer.hpp +++ b/src/rj_ui/include/rj_ui/log_viewer.hpp @@ -25,8 +25,6 @@ class LogViewer : public QMainWindow { public Q_SLOTS: void updateViews(); - void on_actionRawBalls_toggled(bool state); - void on_actionRawRobots_toggled(bool state); void on_actionCoords_toggled(bool state); // Field rotation diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 8d00edba2de..ea1c1647c36 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -106,8 +106,6 @@ private Q_SLOTS: void updateViews(); void on_fieldView_robotSelected(int shell); - void on_actionRawBalls_toggled(bool state); - void on_actionRawRobots_toggled(bool state); void on_actionCoords_toggled(bool state); void on_actionDotPatterns_toggled(bool state); void on_actionTeam_Names_toggled(bool state); diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index 7d2c64be582..9379bcece7a 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -30,7 +30,6 @@ #include "rj_ui/ros2_temp/autonomy_interface.hpp" #include "rj_ui/ros2_temp/debug_draw_interface.hpp" -#include "rj_ui/ros2_temp/raw_vision_packet_sub.hpp" #include "rj_ui/ros2_temp/referee_sub.hpp" #include "rj_ui/ros2_temp/soccer_config_client.hpp" @@ -158,7 +157,6 @@ class Processor { AsyncWorldStateMsgQueue::UniquePtr world_state_queue_; std::unique_ptr config_client_; - std::unique_ptr raw_vision_packet_sub_; std::unique_ptr referee_sub_; std::unique_ptr debug_draw_sub_; std::unique_ptr autonomy_interface_; diff --git a/src/rj_ui/include/rj_ui/ros2_temp/raw_vision_packet_sub.hpp b/src/rj_ui/include/rj_ui/ros2_temp/raw_vision_packet_sub.hpp deleted file mode 100644 index 67829df7b2d..00000000000 --- a/src/rj_ui/include/rj_ui/ros2_temp/raw_vision_packet_sub.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -#include "rj_ui/ros2_temp/raw_vision_packet_sub.hpp" - -namespace ros2_temp { -using RawProtobufMsg = rj_msgs::msg::RawProtobuf; - -/** - * @brief A temporary class (until the logging framework is ported) that obtains - * the raw protobuf messages from vision_receiver by spinning off a thread to - * handle callbacks. - */ -class RawVisionPacketSub { -public: - using UniquePtr = std::unique_ptr; - RawVisionPacketSub(Context* context); - - /** - * @brief Updates context->raw_vision_packets with the raw protobuf message - * from vision_receiver. - */ - void run(); - -private: - Context* context_; - - using RawProtobufMsgQueue = rj_topic_utils::AsyncMessageQueue< - RawProtobufMsg, rj_topic_utils::MessagePolicy::kQueue>; - RawProtobufMsgQueue::UniquePtr queue_; -}; -} // namespace ros2_temp \ No newline at end of file diff --git a/src/rj_ui/qt/LogViewer.ui b/src/rj_ui/qt/LogViewer.ui index 4855d63afb7..43467d8b987 100644 --- a/src/rj_ui/qt/LogViewer.ui +++ b/src/rj_ui/qt/LogViewer.ui @@ -278,8 +278,6 @@ - - @@ -320,22 +318,6 @@ 270 - - - true - - - Raw &Balls - - - - - true - - - Raw &Robots - - true diff --git a/src/rj_ui/qt/MainWindow.ui b/src/rj_ui/qt/MainWindow.ui index 68f3da69cb5..6c31282ea29 100644 --- a/src/rj_ui/qt/MainWindow.ui +++ b/src/rj_ui/qt/MainWindow.ui @@ -3186,8 +3186,6 @@ - - @@ -3288,22 +3286,6 @@ 270 degrees - - - true - - - Raw &Balls - - - - - true - - - Raw &Robots - - true diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index b863968a2a7..9e3524cbcd0 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -44,8 +44,6 @@ static QColor ballColor(0xff, 0x90, 0); static QPen ballPen(ballColor, 0); FieldView::FieldView(QWidget* parent) : QWidget(parent) { - showRawRobots = false; - showRawBalls = false; showCoords = false; showDotPatterns = false; showTeamNames = false; @@ -192,41 +190,6 @@ void FieldView::drawWorldSpace(QPainter& p) { // Draw the field drawField(p, frame); - // Raw vision - if (showRawBalls || showRawRobots) { - tempPen.setColor(QColor(0xcc, 0xcc, 0xcc)); - p.setPen(tempPen); - for (const SSL_WrapperPacket& wrapper : frame->raw_vision()) { - if (!wrapper.has_detection()) { - // Useless - continue; - } - - const SSL_DetectionFrame& detect = wrapper.detection(); - - if (showRawRobots) { - for (const SSL_DetectionRobot& r : detect.robots_blue()) { - QPointF pos(r.x() / 1000, r.y() / 1000); - drawRobot(p, true, r.robot_id(), pos, r.orientation()); - // p.drawEllipse(QPointF(r.x() / 1000, r.y() / 1000), - // kRobotRadius, kRobotRadius); - } - - for (const SSL_DetectionRobot& r : detect.robots_yellow()) { - QPointF pos(r.x() / 1000, r.y() / 1000); - drawRobot(p, false, r.robot_id(), pos, r.orientation()); - // p.drawEllipse(QPointF(r.x() / 1000, r.y() / 1000), - // kRobotRadius, kRobotRadius); - } - } - - if (showRawBalls) { - for (const SSL_DetectionBall& b : detect.balls()) { - p.drawEllipse(QPointF(b.x() / 1000, b.y() / 1000), kBallRadius, kBallRadius); - } - } - } - } } void FieldView::drawTeamSpace(QPainter& p) { diff --git a/src/rj_ui/src/log_viewer.cpp b/src/rj_ui/src/log_viewer.cpp index 5d1779df5fa..c37c5b5d845 100644 --- a/src/rj_ui/src/log_viewer.cpp +++ b/src/rj_ui/src/log_viewer.cpp @@ -155,16 +155,6 @@ void LogViewer::on_action180_triggered() { ui.fieldView->rotate(2); } void LogViewer::on_action270_triggered() { ui.fieldView->rotate(3); } -void LogViewer::on_actionRawBalls_toggled(bool state) { - ui.fieldView->showRawBalls = state; - ui.fieldView->update(); -} - -void LogViewer::on_actionRawRobots_toggled(bool state) { - ui.fieldView->showRawRobots = state; - ui.fieldView->update(); -} - void LogViewer::on_actionCoords_toggled(bool state) { ui.fieldView->showCoords = state; ui.fieldView->update(); diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index c54037d58d9..1159da0f5b9 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -799,16 +799,6 @@ void MainWindow::on_fieldView_robotSelected(int shell) { } } -void MainWindow::on_actionRawBalls_toggled(bool state) { - _ui.fieldView->showRawBalls = state; - _ui.fieldView->update(); -} - -void MainWindow::on_actionRawRobots_toggled(bool state) { - _ui.fieldView->showRawRobots = state; - _ui.fieldView->update(); -} - void MainWindow::on_actionCoords_toggled(bool state) { _ui.fieldView->showCoords = state; _ui.fieldView->update(); diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index 77d822c34e8..8e951458ffd 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -24,7 +24,6 @@ Processor::Processor(bool sim, bool blue_team, const std::string& read_log_file) // ROS2 temp nodes config_client_ = std::make_unique(&context_); - raw_vision_packet_sub_ = std::make_unique(&context_); referee_sub_ = std::make_unique(&context_, ros_executor_.get()); debug_draw_sub_ = @@ -86,9 +85,6 @@ void Processor::run() { // Updates context_->field_dimensions config_client_->run(); - // Updates context_->raw_vision_packets - raw_vision_packet_sub_->run(); - if (context_.field_dimensions != *current_dimensions) { SPDLOG_INFO("Updating field geometry based off of vision packet."); set_field_dimensions(context_.field_dimensions); diff --git a/src/rj_ui/src/ros2_temp/raw_vision_packet_sub.cpp b/src/rj_ui/src/ros2_temp/raw_vision_packet_sub.cpp deleted file mode 100644 index 893f0754b36..00000000000 --- a/src/rj_ui/src/ros2_temp/raw_vision_packet_sub.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "rj_ui/ros2_temp/raw_vision_packet_sub.hpp" - -namespace ros2_temp { -RawVisionPacketSub::RawVisionPacketSub(Context* context) : context_{context} { - queue_ = std::make_unique("raw_vision_packet_sub", - vision_receiver::topics::kRawProtobufTopic); -} - -void RawVisionPacketSub::run() { - std::vector raw_protobufs = queue_->get_all(); - - // Convert all RawProtobufMsgs to SSL_WrapperPacket - for (const RawProtobufMsg::UniquePtr& msg : raw_protobufs) { - context_->raw_vision_packets.emplace_back(); - context_->raw_vision_packets.back().ParseFromArray(msg->data.data(), msg->data.size()); - } -} - -} // namespace ros2_temp From 4cfdb4b0f0a3422062674980dc935f7d853d31d5 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Sep 2026 13:46:58 -0400 Subject: [PATCH 02/21] test --- src/rj_common/CMakeLists.txt | 3 - src/rj_common/include/rj_common/context.hpp | 46 -- .../include/rj_common/debug_drawer.hpp | 84 +-- src/rj_common/include/rj_common/logger.hpp | 75 --- .../rj_common/radio/packet_convert.hpp | 7 - src/rj_common/src/debug_drawer.cpp | 122 ---- src/rj_common/src/logger.cpp | 281 ---------- src/rj_common/src/planning/trajectory.cpp | 11 - src/rj_common/src/radio/packet_convert.cpp | 82 --- src/rj_common/tests/logger_test.cpp | 85 --- src/rj_geometry/include/rj_geometry/point.hpp | 11 - src/rj_protos/CMakeLists.txt | 6 - src/rj_protos/protos/Control.proto | 32 -- src/rj_protos/protos/LogFrame.proto | 169 ------ src/rj_protos/protos/Point.proto | 7 - src/rj_protos/protos/RadioRx.proto | 52 -- src/rj_protos/protos/RadioTx.proto | 8 - src/rj_protos/protos/Robot.proto | 10 - src/rj_radio/src/sim_radio.cpp | 1 - .../include/rj_referee/external_referee.hpp | 1 - src/rj_ui/CMakeLists.txt | 36 +- src/rj_ui/include/rj_ui/field_view.hpp | 11 +- src/rj_ui/include/rj_ui/live_frame.hpp | 169 ++++++ src/rj_ui/include/rj_ui/log_viewer.hpp | 58 -- src/rj_ui/include/rj_ui/main_window.hpp | 66 +-- src/rj_ui/include/rj_ui/processor.hpp | 17 +- src/rj_ui/include/rj_ui/protobuf_tree.hpp | 70 --- .../include/rj_ui/robot_status_widget.hpp | 8 +- src/rj_ui/include/rj_ui/strip_chart.hpp | 110 ---- src/rj_ui/qt/LogViewer.ui | 348 ------------ src/rj_ui/qt/MainWindow.ui | 8 +- src/rj_ui/src/field_view.cpp | 27 +- src/rj_ui/src/log_viewer.cpp | 184 ------ src/rj_ui/src/log_viewer_main.cpp | 39 -- src/rj_ui/src/main.cpp | 32 +- src/rj_ui/src/main_window.cpp | 149 +++-- src/rj_ui/src/processor.cpp | 22 +- src/rj_ui/src/protobuf_tree.cpp | 525 ------------------ src/rj_ui/src/robot_status_widget.cpp | 214 ++----- .../src/ros2_temp/debug_draw_interface.cpp | 10 - src/rj_ui/src/sim_field_view.cpp | 9 +- src/rj_ui/src/strip_chart.cpp | 302 ---------- src/rj_utils/CMakeLists.txt | 2 + src/rj_utils/include/rj_utils/log_utils.hpp | 8 +- src/rj_utils/package.xml | 1 + 45 files changed, 334 insertions(+), 3184 deletions(-) delete mode 100644 src/rj_common/include/rj_common/logger.hpp delete mode 100644 src/rj_common/src/debug_drawer.cpp delete mode 100644 src/rj_common/src/logger.cpp delete mode 100644 src/rj_common/tests/logger_test.cpp delete mode 100644 src/rj_protos/protos/Control.proto delete mode 100644 src/rj_protos/protos/LogFrame.proto delete mode 100644 src/rj_protos/protos/Point.proto delete mode 100644 src/rj_protos/protos/RadioRx.proto delete mode 100644 src/rj_protos/protos/RadioTx.proto delete mode 100644 src/rj_protos/protos/Robot.proto create mode 100644 src/rj_ui/include/rj_ui/live_frame.hpp delete mode 100644 src/rj_ui/include/rj_ui/log_viewer.hpp delete mode 100644 src/rj_ui/include/rj_ui/protobuf_tree.hpp delete mode 100644 src/rj_ui/include/rj_ui/strip_chart.hpp delete mode 100644 src/rj_ui/qt/LogViewer.ui delete mode 100644 src/rj_ui/src/log_viewer.cpp delete mode 100644 src/rj_ui/src/log_viewer_main.cpp delete mode 100644 src/rj_ui/src/protobuf_tree.cpp delete mode 100644 src/rj_ui/src/strip_chart.cpp diff --git a/src/rj_common/CMakeLists.txt b/src/rj_common/CMakeLists.txt index 5ab64ff847d..632788f67a2 100644 --- a/src/rj_common/CMakeLists.txt +++ b/src/rj_common/CMakeLists.txt @@ -37,9 +37,7 @@ set(RJ_COMMON_DEPS ) add_library(${PROJECT_NAME} SHARED - src/debug_drawer.cpp src/field_dimensions.cpp - src/logger.cpp src/multicast.cpp src/qt_utils.cpp src/referee_enums.cpp @@ -100,7 +98,6 @@ if(BUILD_TESTING) set(RJ_COMMON_TESTS ball_test game_state_test - logger_test rj_common_convert_test world_state_test ) diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 426416089cd..f98d07cb5b8 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -16,51 +16,6 @@ #include "rj_common/team_info.hpp" #include "rj_common/world_state.hpp" -// Keep the past thirty minutes of logs by default. -constexpr size_t kMaxLogFrames = 60 * 60 * 30; - -struct Logs { - /** - * \brief A list of all log frames. This will contain at most - * `kMaxLogFrames` frames. - * - * This should not be accessed from the Processor thread, other - * than to add frames. The container may be accessed by the MainWindow - * thread while the Context mutex is locked, and frames may be retained - * and used even while the mutex is not locked (provided a shared_ptr - * is kept). - */ - std::deque> frames; - - enum class State { kNoFile, kWriting, kReading }; - - /** - * \brief The name of the log file, if it exists. - */ - std::optional filename; - - /** - * \brief Whether we are recording (or viewing) logs. - */ - State state = State::kNoFile; - - /** - * \brief The start time of the entire system. - */ - RJ::Time start_time; - - /** - * \brief The log file size in bytes. - */ - size_t size_bytes = 0; - - /** - * The count of frames that existed before the given history - * but were dropped. - */ - size_t dropped_frames = 0; -}; - struct Context { Context() : debug_drawer(this) {} @@ -105,6 +60,5 @@ struct Context { GameSettings game_settings; - Logs logs; std::string behavior_tree; }; diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 857de0ad5dc..5b814c8f1d7 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -13,14 +13,13 @@ #include #include #include -#include #include struct Context; class DebugDrawer { public: - DebugDrawer(Context* context) : num_debug_layers_(0), context_(context) { reset_log_frame(); } + DebugDrawer(Context* context) : num_debug_layers_(0), context_(context) {} const QStringList& debug_layers() const { return debug_layers_; } @@ -28,83 +27,50 @@ class DebugDrawer { int find_debug_layer(QString layer); /** @ingroup drawing_functions */ - void draw_polygon(const rj_geometry::Point* pts, int n, - const QColor& qc = Qt::black, - const QString& layer = QString()); + void draw_polygon(const rj_geometry::Point*, int, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_polygon(const std::vector& pts, - const QColor& qc = Qt::black, - const QString& layer = QString()); + void draw_polygon(const std::vector&, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_polygon(const rj_geometry::Polygon& pts, - const QColor& qc = Qt::black, - const QString& layer = QString()); + void draw_polygon(const rj_geometry::Polygon&, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_circle(rj_geometry::Point center, float radius, - const QColor& qc = Qt::black, - const QString& layer = QString()); + void draw_circle(rj_geometry::Point, float, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_arc(const rj_geometry::Arc& arc, const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_arc(const rj_geometry::Arc&, const QColor& = Qt::black, + const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_shape(const std::shared_ptr& obs, - const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_shape(const std::shared_ptr&, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_shape_set(const rj_geometry::ShapeSet& shapes, - const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_shape_set(const rj_geometry::ShapeSet&, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_line(const rj_geometry::Segment& line, const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_line(const rj_geometry::Segment&, const QColor& = Qt::black, + const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_line(rj_geometry::Point p0, rj_geometry::Point p1, - const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_line(rj_geometry::Point, rj_geometry::Point, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_text(const QString& text, rj_geometry::Point pos, - const QColor& qw = Qt::black, - const QString& layer = QString()); + void draw_text(const QString&, rj_geometry::Point, + const QColor& = Qt::black, const QString& = QString()) {} /** @ingroup drawing_functions */ - void draw_segment(const rj_geometry::Segment& line, - const QColor& qw = Qt::black, - const QString& layer = QString()); - - /** - * Fill the given log frame with the current debug drawing information, - * and reset our current debug drawing data for the next cycle. - * - * @param log_frame - */ - void fill_log_frame(Packet::LogFrame* log_frame) { - log_frame->MergeFrom(log_frame_); - reset_log_frame(); - } - - /** - * Helper pass-through method to create a new debug path. - */ - Packet::DebugRobotPath* add_debug_path() { - return log_frame_.add_debug_robot_paths(); - } + void draw_segment(const rj_geometry::Segment&, const QColor& = Qt::black, + const QString& = QString()) {} private: - void reset_log_frame() { - log_frame_.Clear(); - for (const QString& string : debug_layers_) { - log_frame_.add_debug_layers(string.toStdString()); - } - } /// Number of debug layers int num_debug_layers_; @@ -116,8 +82,4 @@ class DebugDrawer { Context* context_; - // Keep an entire log frame, but only fill the parts related to debug - // drawing. Then we can use protobuf's merge functionality to merge it into - // the main log frame. - Packet::LogFrame log_frame_; }; diff --git a/src/rj_common/include/rj_common/logger.hpp b/src/rj_common/include/rj_common/logger.hpp deleted file mode 100644 index 25bcef85f70..00000000000 --- a/src/rj_common/include/rj_common/logger.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "rj_common/context.hpp" -#include "rj_common/control/motion_setpoint.hpp" -#include "rj_common/node.hpp" -#include "rj_common/radio/packet_convert.hpp" -#include "rj_common/radio/robot_status.hpp" -#include "rj_common/robot_intent.hpp" -#include "rj_common/time.hpp" -#include "rj_common/world_state.hpp" - -// For FRIEND_TEST -// #include - -/** - * \brief Populates the log frame in Context, and writes it to a file. - * - * When viewing logs, reads logs from a file and populates the log frame. - */ -class Logger : public Node { -public: - Logger(Context* context) : context_(context) {} - - /** - * \brief Open the given file for reading - */ - void read(const std::string& filename); - - /** - * \brief Open the given file for writing. - */ - void write(const std::string& filename); - - /** - * \brief Close the current log file. - */ - void close(); - - /** - * \brief Flush the file to disk. - */ - - void start() override; - void run() override; - void stop() override; - -private: - static std::shared_ptr create_log_frame(Context* context); - static bool write_to_file(Packet::LogFrame* frame, - google::protobuf::io::ZeroCopyOutputStream* out); - static bool read_from_file(Packet::LogFrame* frame, - google::protobuf::io::ZeroCopyInputStream* in); - static void fill_robot(Packet::LogFrame::Robot* out, int shell_id, - RobotState const* state, RobotStatus const* status, - MotionSetpoint const* setpoint); - - FRIEND_TEST(Logger, SaveContext); - FRIEND_TEST(Logger, SerializeDeserialize); - - std::optional log_file_; - - Context* context_; -}; diff --git a/src/rj_common/include/rj_common/radio/packet_convert.hpp b/src/rj_common/include/rj_common/radio/packet_convert.hpp index c86c8c755cc..7557d007876 100644 --- a/src/rj_common/include/rj_common/radio/packet_convert.hpp +++ b/src/rj_common/include/rj_common/radio/packet_convert.hpp @@ -9,9 +9,6 @@ #include #include #include -#include -#include -#include #include #include @@ -31,7 +28,6 @@ * - RTP. This is the packed format we use to send to and from real robots * - sim. This is a protobuf-based format used to communicate with sim * - RobotStatus. This is the in-memory representation used in Context. - * - Packet::RadioRx. This is the representation used in the log frame. * * For Tx (soccer to robot), the structs are similar with one exception: * instead of a single equivalent to RobotStatus, in-memory representations of @@ -44,7 +40,6 @@ void rtp_to_status(const RadioMessage::RobotStatusMessage& rtp, RobotStatus* sta void sim_to_status(const RobotFeedback& sim, RobotStatus* status); -void status_to_proto(const RobotStatus& status, Packet::RadioRx* proto); void status_to_ros(const RobotStatus& status, rj_msgs::msg::RobotStatus* msg); @@ -61,8 +56,6 @@ void ros_to_rtp(const rj_msgs::msg::ManipulatorSetpoint& manipulator, const rj_msgs::msg::MotionSetpoint& motion, int shell, RadioMessage::ControlMessage* rtp, strategy::Positions role, bool blue_team); -void to_proto(const planning::Trajectory& trajectory, const RobotIntent& intent, - const MotionSetpoint& setpoint, int shell, Packet::Robot* proto); void to_sim(const RobotIntent& intent, const MotionSetpoint& setpoint, int shell, RobotCommand* sim); diff --git a/src/rj_common/src/debug_drawer.cpp b/src/rj_common/src/debug_drawer.cpp deleted file mode 100644 index 02736f238c6..00000000000 --- a/src/rj_common/src/debug_drawer.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "rj_common/debug_drawer.hpp" - -int DebugDrawer::find_debug_layer(QString layer) { - if (layer.isNull()) { - layer = "Debug"; - } - - QMap::const_iterator i = debug_layer_map_.find(layer); - if (i == debug_layer_map_.end()) { - // New layer - int n = num_debug_layers_++; - debug_layer_map_[layer] = n; - debug_layers_.append(layer); - return n; - } - // Existing layer - return i.value(); -} - -void DebugDrawer::draw_polygon(const rj_geometry::Point* pts, int n, const QColor& qc, - const QString& layer) { - Packet::DebugPath* dbg = log_frame_.add_debug_polygons(); - dbg->set_layer(find_debug_layer(layer)); - for (int i = 0; i < n; ++i) { - *dbg->add_points() = pts[i]; - } - dbg->set_color(color(qc)); -} - -void DebugDrawer::draw_polygon(const std::vector& pts, const QColor& qc, - const QString& layer) { - draw_polygon(pts.data(), pts.size(), qc, layer); -} - -void DebugDrawer::draw_polygon(const rj_geometry::Polygon& polygon, const QColor& qc, - const QString& layer) { - this->draw_polygon(polygon.vertices, qc, layer); -} - -void DebugDrawer::draw_circle(rj_geometry::Point center, float radius, const QColor& qc, - const QString& layer) { - Packet::DebugCircle* dbg = log_frame_.add_debug_circles(); - dbg->set_layer(find_debug_layer(layer)); - *dbg->mutable_center() = center; - dbg->set_radius(radius); - dbg->set_color(color(qc)); -} - -void DebugDrawer::draw_arc(const rj_geometry::Arc& arc, const QColor& qc, const QString& layer) { - Packet::DebugArc* dbg = log_frame_.add_debug_arcs(); - dbg->set_layer(find_debug_layer(layer)); - *dbg->mutable_center() = arc.center(); - dbg->set_radius(arc.radius()); - dbg->set_start(arc.start()); - dbg->set_end(arc.end()); - dbg->set_color(color(qc)); -} - -void DebugDrawer::draw_shape(const std::shared_ptr& obs, const QColor& color, - const QString& layer) { - std::shared_ptr circ_obs = - std::dynamic_pointer_cast(obs); - std::shared_ptr poly_obs = - std::dynamic_pointer_cast(obs); - std::shared_ptr comp_obs = - std::dynamic_pointer_cast(obs); - std::shared_ptr rect_obs = std::dynamic_pointer_cast(obs); - if (circ_obs) - draw_circle(circ_obs->center, circ_obs->radius(), color, layer); - else if (poly_obs) - draw_polygon(poly_obs->vertices, color, layer); - else if (rect_obs) { - std::vector points = { - rj_geometry::Point{rect_obs->minx(), rect_obs->miny()}, - rj_geometry::Point{rect_obs->maxx(), rect_obs->miny()}, - rj_geometry::Point{rect_obs->maxx(), rect_obs->maxy()}, - rj_geometry::Point{rect_obs->minx(), rect_obs->maxy()}}; - draw_polygon(points.data(), points.size(), color, layer); - } else if (comp_obs) { - for (const std::shared_ptr& obs : comp_obs->subshapes()) - draw_shape(obs, color, layer); - } -} - -void DebugDrawer::draw_shape_set(const rj_geometry::ShapeSet& shapes, const QColor& color, - const QString& layer) { - for (auto& shape : shapes.shapes()) { - draw_shape(shape, color, layer); - } -} - -void DebugDrawer::draw_line(const rj_geometry::Segment& line, const QColor& qc, - const QString& layer) { - Packet::DebugPath* dbg = log_frame_.add_debug_paths(); - dbg->set_layer(find_debug_layer(layer)); - *dbg->add_points() = line.pt[0]; - *dbg->add_points() = line.pt[1]; - dbg->set_color(color(qc)); -} - -void DebugDrawer::draw_line(rj_geometry::Point p0, rj_geometry::Point p1, const QColor& color, - const QString& layer) { - draw_line(rj_geometry::Segment(p0, p1), color, layer); -} - -void DebugDrawer::draw_text(const QString& text, rj_geometry::Point pos, const QColor& qc, - const QString& layer) { - Packet::DebugText* dbg = log_frame_.add_debug_texts(); - dbg->set_layer(find_debug_layer(layer)); - dbg->set_text(text.toStdString()); - *dbg->mutable_pos() = pos; - dbg->set_color(color(qc)); -} - -void DebugDrawer::draw_segment(const rj_geometry::Segment& line, const QColor& qc, - const QString& layer) { - Packet::DebugPath* dbg = log_frame_.add_debug_paths(); - dbg->set_layer(find_debug_layer(layer)); - *dbg->add_points() = line.pt[0]; - *dbg->add_points() = line.pt[1]; - dbg->set_color(color(qc)); -} \ No newline at end of file diff --git a/src/rj_common/src/logger.cpp b/src/rj_common/src/logger.cpp deleted file mode 100644 index 400e9aa58fa..00000000000 --- a/src/rj_common/src/logger.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include "rj_common/logger.hpp" - -using namespace Packet; - -// Protobuf helper function from: https://stackoverflow.com/a/22927149: -// From Comment: -// (I am the author of the C++ and Java protobuf libraries, but I no longer work -// for Google. Sorry that this code never made it into the official lib. This is -// what it would look like if it had.) - -/** - * Write a message to an output stream, delimited by size. - */ -bool write_delimited_to(const google::protobuf::MessageLite& message, - google::protobuf::io::ZeroCopyOutputStream* raw_output) { - // We create a new coded stream for each message. Don't worry, this is - // fast. - google::protobuf::io::CodedOutputStream output(raw_output); - - // Write the size. - const int size = message.ByteSizeLong(); - output.WriteVarint32(size); - - uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size); - if (buffer != nullptr) { - // Optimization: The message fits in one buffer, so use the faster - // direct-to-array serialization path. - message.SerializeWithCachedSizesToArray(buffer); - } else { - // Slightly-slower path when the message is multiple buffers. - message.SerializeWithCachedSizes(&output); - if (output.HadError()) { - return false; - } - } - - return true; -} - -/** - * Read a message from an input stream, delimited by size. - */ -bool read_delimited_from(google::protobuf::io::ZeroCopyInputStream* raw_input, - google::protobuf::MessageLite* message) { - // We create a new coded stream for each message. Don't worry, this is - // fast, and it makes sure the 64MB total size limit is imposed per-message - // rather than on the whole stream. (See the CodedInputStream interface for - // more info on this limit.) - google::protobuf::io::CodedInputStream input(raw_input); - - // Read the size. - uint32_t size = 0; - if (!input.ReadVarint32(&size)) { - return false; - } - - // Tell the stream not to read beyond that size. - google::protobuf::io::CodedInputStream::Limit limit = input.PushLimit(size); - - // Parse the message. - if (!message->MergeFromCodedStream(&input)) { - return false; - } - if (!input.ConsumedEntireMessage()) { - return false; - } - - // Release the limit. - input.PopLimit(limit); - - return true; -} - -void Logger::start() { - context_->logs.start_time = RJ::now(); - - // Log a message that is empty except for a log config and a start time. - std::shared_ptr log_frame = std::make_shared(); - log_frame->set_timestamp( - std::chrono::duration_cast(RJ::now().time_since_epoch()) - .count()); - - log_frame->mutable_log_config()->set_generator("soccer"); - log_frame->mutable_log_config()->set_simulation(context_->game_settings.simulation); -} - -void Logger::run() { - std::shared_ptr log_frame = create_log_frame(context_); - - if (context_->logs.state == Logs::State::kWriting) { - context_->logs.size_bytes += log_frame->ByteSizeLong(); - google::protobuf::io::OstreamOutputStream output(&log_file_.value()); - write_to_file(log_frame.get(), &output); - } - - while (context_->logs.frames.size() + 1 >= kMaxLogFrames) { - context_->logs.frames.pop_front(); - } - - context_->logs.frames.emplace_back(std::move(log_frame)); -} - -void Logger::stop() {} - -void Logger::read(const std::string& filename) { - log_file_ = std::fstream(); - log_file_->open(filename, std::fstream::in | std::fstream::binary); - context_->logs.filename = filename; - context_->logs.state = Logs::State::kReading; - - context_->logs.frames.clear(); - - if (!log_file_->good()) { - FATAL_THROW("Log file {} does not exist.", filename); - } - - // Populate the entire logs struct. - auto frame = std::make_shared(); - google::protobuf::io::IstreamInputStream input(&log_file_.value()); - while (read_from_file(frame.get(), &input)) { - context_->logs.size_bytes += frame->ByteSizeLong(); - context_->logs.frames.emplace_back(std::move(frame)); - frame = std::make_shared(); - } -} - -void Logger::write(const std::string& filename) { - log_file_ = std::fstream(); - log_file_->open(filename, std::fstream::out | std::fstream::binary); - context_->logs.filename = filename; - context_->logs.state = Logs::State::kWriting; - - google::protobuf::io::OstreamOutputStream output(&log_file_.value()); - for (const auto& frame : context_->logs.frames) { - write_to_file(frame.get(), &output); - } -} - -void Logger::close() { - log_file_ = std::nullopt; - context_->logs.filename = std::nullopt; - context_->logs.state = Logs::State::kNoFile; -} - -std::shared_ptr Logger::create_log_frame(Context* context) { - // Add everything to the log frame. - auto log_frame = std::make_shared(); - - // Debug drawing - context->debug_drawer.fill_log_frame(log_frame.get()); - - // Copy referee packets. - for (const auto& packet : context->referee_packets) { - Referee* referee = log_frame->add_raw_refbox(); - referee->CopyFrom(packet); - } - context->referee_packets.clear(); - - log_frame->set_blue_team(context->blue_team); - log_frame->set_command_time(RJ::timestamp()); - - // Our robots - for (size_t shell = 0; shell < kNumShells; shell++) { - const auto& state = context->world_state.our_robots.at(shell); - const auto& status = context->robot_status.at(shell); - const auto& setpoint = context->motion_setpoints.at(shell); - - if (!state.visible) { - continue; - } - - LogFrame::Robot* robot = log_frame->add_self(); - fill_robot(robot, shell, &state, &status, &setpoint); - } - - // Radio RX/TX for each robot - for (size_t shell = 0; shell < kNumShells; shell++) { - const auto& status = context->robot_status.at(shell); - if (RJ::now() - status.timestamp > RJ::Seconds(0.5)) { - continue; - } - const auto& trajectory = context->trajectories.at(shell); - const auto& intent = context->robot_intents.at(shell); - const auto& setpoint = context->motion_setpoints.at(shell); - - RadioRx* rx = log_frame->add_radio_rx(); - ConvertRx::status_to_proto(status, rx); - - Packet::Robot* tx = log_frame->mutable_radio_tx()->add_robots(); - ConvertTx::to_proto(trajectory, intent, setpoint, static_cast(shell), tx); - } - - // Opponent robots - for (size_t shell = 0; shell < kNumShells; shell++) { - const auto& state = context->world_state.their_robots.at(shell); - if (!state.visible) { - continue; - } - - LogFrame::Robot* robot = log_frame->add_opp(); - fill_robot(robot, shell, &state, nullptr, nullptr); - } - - // Ball - if (context->world_state.ball.visible) { - log_frame->mutable_ball()->mutable_pos()->set_x( - static_cast(context->world_state.ball.position.x())); - log_frame->mutable_ball()->mutable_pos()->set_y( - static_cast(context->world_state.ball.position.y())); - log_frame->mutable_ball()->mutable_vel()->set_x( - static_cast(context->world_state.ball.velocity.x())); - log_frame->mutable_ball()->mutable_vel()->set_y( - static_cast(context->world_state.ball.velocity.y())); - } - - log_frame->set_manual_id(context->game_settings.joystick_config.manual_id); - log_frame->set_defend_plus_x(context->game_settings.defend_plus_x); - log_frame->set_use_our_half(context->game_settings.use_our_half); - log_frame->set_use_opponent_half(context->game_settings.use_their_half); - - // Behavior tree - log_frame->set_behavior_tree(context->behavior_tree); - - // Team names - if (context->blue_team) { - log_frame->set_team_name_yellow(context->their_info.name); - log_frame->set_team_name_blue(context->our_info.name); - } else { - log_frame->set_team_name_yellow(context->our_info.name); - log_frame->set_team_name_blue(context->their_info.name); - } - - log_frame->set_timestamp(RJ::timestamp()); - - return log_frame; -} - -bool Logger::write_to_file(Packet::LogFrame* frame, - google::protobuf::io::ZeroCopyOutputStream* out) { - return write_delimited_to(*frame, out); -} - -bool Logger::read_from_file(Packet::LogFrame* frame, - google::protobuf::io::ZeroCopyInputStream* in) { - return read_delimited_from(in, frame); -} - -void Logger::fill_robot(Packet::LogFrame::Robot* out, int shell_id, RobotState const* state, - RobotStatus const* status, MotionSetpoint const* setpoint) { - out->set_shell(shell_id); - - if (state != nullptr) { - out->mutable_pos()->set_x(static_cast(state->pose.position().x())); - out->mutable_pos()->set_y(static_cast(state->pose.position().y())); - out->set_angle(static_cast(state->pose.heading())); - out->mutable_world_vel()->set_x(static_cast(state->velocity.linear().x())); - out->mutable_world_vel()->set_y(static_cast(state->velocity.linear().y())); - } - - if (status != nullptr) { - out->set_ball_sense_status(status->has_ball ? BallSenseStatus::HasBall - : BallSenseStatus::NoBall); - - out->set_charged(status->kicker == RobotStatus::KickerState::kCharged); - out->set_kicker_voltage(static_cast(status->kicker_voltage)); - - for (int i = 0; i < 5; i++) { - out->add_motor_status(status->motors_healthy[i] ? MotorStatus::Good - : MotorStatus::Encoder_Failure); - } - - out->set_kicker_works(status->kicker != RobotStatus::KickerState::kFailed); - out->set_battery_voltage(static_cast(status->battery_voltage)); - } - - if (setpoint != nullptr) { - out->mutable_cmd_vel()->set_x(static_cast(setpoint->xvelocity)); - out->mutable_cmd_vel()->set_y(static_cast(setpoint->yvelocity)); - out->set_cmd_w(static_cast(setpoint->avelocity)); - } -} diff --git a/src/rj_common/src/planning/trajectory.cpp b/src/rj_common/src/planning/trajectory.cpp index a25a7f64a60..2d1a7049043 100644 --- a/src/rj_common/src/planning/trajectory.cpp +++ b/src/rj_common/src/planning/trajectory.cpp @@ -183,17 +183,6 @@ Trajectory::Cursor Trajectory::cursor_begin() const { return Cursor{*this, insta void Trajectory::draw(DebugDrawer* drawer, std::optional alt_text_position) const { - if (instants_.size() > 1) { - Packet::DebugRobotPath* dbg_path = drawer->add_debug_path(); - dbg_path->set_layer(drawer->find_debug_layer("Motion")); - - for (const RobotInstant& instant : instants_) { - Packet::DebugRobotPath::DebugRobotPathPoint* pt = dbg_path->add_points(); - *pt->mutable_pos() = instant.pose.position(); - *pt->mutable_vel() = instant.velocity.linear(); - } - } - if (debug_text_) { rj_geometry::Point text_pos; diff --git a/src/rj_common/src/radio/packet_convert.cpp b/src/rj_common/src/radio/packet_convert.cpp index e7dc649fb8c..57c54670c60 100644 --- a/src/rj_common/src/radio/packet_convert.cpp +++ b/src/rj_common/src/radio/packet_convert.cpp @@ -69,51 +69,6 @@ void sim_to_status(const RobotFeedback& sim, RobotStatus* status) { status->fpga_healthy = true; } -void status_to_proto(const RobotStatus& status, Packet::RadioRx* proto) { - using namespace std::chrono; - - proto->set_timestamp(duration_cast(status.timestamp.time_since_epoch()).count()); - proto->set_robot_id(status.shell_id); - proto->set_battery(static_cast(status.battery_voltage)); - - proto->set_ball_sense_status(status.has_ball ? Packet::BallSenseStatus::HasBall - : Packet::BallSenseStatus::NoBall); - - for (int i = 0; i < 5; i++) { - proto->add_motor_status(status.motors_healthy[i] ? Packet::MotorStatus::Good - : Packet::MotorStatus::Encoder_Failure); - } - - // No encoders or RSSI - - switch (status.kicker) { - case RobotStatus::KickerState::kFailed: - proto->set_kicker_status(Kicker_I2C_OK); - break; - case RobotStatus::KickerState::kCharging: - proto->set_kicker_status(Kicker_Enabled | Kicker_I2C_OK); - break; - case RobotStatus::KickerState::kCharged: - proto->set_kicker_status(Kicker_Charged | Kicker_Enabled | Kicker_I2C_OK); - break; - } - - proto->set_kicker_voltage(status.kicker_voltage); - proto->set_fpga_status(status.fpga_healthy ? Packet::FpgaStatus::FpgaGood - : Packet::FpgaStatus::FpgaError); - - switch (status.version) { - case RobotStatus::HardwareVersion::kUnknown: - proto->set_hardware_version(Packet::HardwareVersion::Unknown); - break; - case RobotStatus::HardwareVersion::kFleet2018: - proto->set_hardware_version(Packet::HardwareVersion::RJ2018); - break; - case RobotStatus::HardwareVersion::kSimulated: - proto->set_hardware_version(Packet::HardwareVersion::Simulation); - break; - } -} void status_to_ros(const RobotStatus& status, rj_msgs::msg::RobotStatus* msg) { rj_convert::convert_to_ros(status.timestamp, &(msg->timestamp)); msg->robot_id = status.shell_id; @@ -189,43 +144,6 @@ void to_rtp(const RobotIntent& intent, const MotionSetpoint& setpoint, int shell } } -void to_proto(const planning::Trajectory& trajectory, const RobotIntent& intent, - const MotionSetpoint& setpoint, int shell, Packet::Robot* proto) { - if (proto == nullptr) { - return; - } - - proto->set_uid(shell); - - Packet::Control* control = proto->mutable_control(); - - control->set_xvelocity(static_cast(setpoint.xvelocity)); - control->set_yvelocity(static_cast(setpoint.yvelocity)); - control->set_avelocity(static_cast(setpoint.avelocity)); - control->set_dvelocity(trajectory.dribbler_speed); - control->set_kcstrength(kicker_speed_to_strength(intent.kick_speed)); - - switch (trajectory.shoot_mode) { - case RobotIntent::ShootMode::KICK: - control->set_shootmode(Packet::Control_ShootMode_KICK); - break; - case RobotIntent::ShootMode::CHIP: - control->set_shootmode(Packet::Control_ShootMode_CHIP); - break; - } - - switch (trajectory.trigger_mode) { - case RobotIntent::TriggerMode::STAND_DOWN: - control->set_triggermode(Packet::Control_TriggerMode_STAND_DOWN); - break; - case RobotIntent::TriggerMode::IMMEDIATE: - control->set_triggermode(Packet::Control_TriggerMode_IMMEDIATE); - break; - case RobotIntent::TriggerMode::ON_BREAK_BEAM: - control->set_triggermode(Packet::Control_TriggerMode_ON_BREAK_BEAM); - break; - } -} void to_sim(const RobotIntent& intent, const MotionSetpoint& setpoint, int shell, RobotCommand* sim) { diff --git a/src/rj_common/tests/logger_test.cpp b/src/rj_common/tests/logger_test.cpp deleted file mode 100644 index 94f5c5c50a6..00000000000 --- a/src/rj_common/tests/logger_test.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "rj_common/logger.hpp" - -#include -#include -#include - -#include "rj_common/context.hpp" - -// NOLINTNEXTLINE -TEST(Logger, SaveContext) { - RJ::Time start_time = RJ::now(); - - // Make sure the logger saves stuff from Context. This is not anywhere near - // exhaustive, it just gets a few items. - Context context; - - // It should save robot states, and their radio packets - context.world_state.our_robots.at(0) = - RobotState{rj_geometry::Pose(1, 2, 3), rj_geometry::Twist(4, 5, 6), start_time, true}; - context.robot_status.at(0).timestamp = start_time; - context.robot_status.at(0).kicker = RobotStatus::KickerState::kCharged; - - // It should not save invisible robots though - context.world_state.our_robots.at(1) = - RobotState{rj_geometry::Pose(1, 2, 3), rj_geometry::Twist(4, 5, 6), start_time, false}; - - // Or their radio packets - context.robot_status.at(1).kicker = RobotStatus::KickerState::kFailed; - - // We should use blue_team from GameState, not GameSettings - context.game_settings.request_blue_team = true; - context.blue_team = false; - - std::shared_ptr frame = Logger::create_log_frame(&context); - - EXPECT_EQ(frame->self_size(), 1); - EXPECT_EQ(frame->self(0).shell(), 0); - EXPECT_EQ(frame->self(0).pos().x(), 1); - EXPECT_EQ(frame->self(0).pos().y(), 2); - EXPECT_EQ(frame->self(0).angle(), 3); - EXPECT_EQ(frame->radio_rx_size(), 1); - - EXPECT_EQ(frame->blue_team(), false); -} - -// NOLINTNEXTLINE -TEST(Logger, SerializeDeserialize) { - // Make a simple log frame - Context context; - - RJ::Time start_time = RJ::now(); - context.world_state.our_robots.at(0) = - RobotState{rj_geometry::Pose(1, 2, 3), rj_geometry::Twist(4, 5, 6), start_time, true}; - context.robot_status.at(0).timestamp = start_time; - context.robot_status.at(0).kicker = RobotStatus::KickerState::kCharged; - - std::shared_ptr frame = Logger::create_log_frame(&context); - - // Allocate 1MiB - std::vector data(1 << 20); - google::protobuf::io::ArrayOutputStream output(data.data(), data.size()); - - constexpr int kExpected = 3; - for (int i = 0; i < 3; i++) { - EXPECT_TRUE(Logger::write_to_file(frame.get(), &output)); - } - - Packet::LogFrame other_frame; - int count = 0; - - google::protobuf::util::MessageDifferencer differencer; - std::string diff; - differencer.ReportDifferencesToString(&diff); - - google::protobuf::io::ArrayInputStream input(data.data(), output.ByteCount()); - while (Logger::read_from_file(&other_frame, &input)) { - count++; - EXPECT_TRUE(differencer.Compare(*frame, other_frame)); - other_frame.Clear(); - } - - std::cout << diff << std::endl; - - EXPECT_EQ(kExpected, count); -} \ No newline at end of file diff --git a/src/rj_geometry/include/rj_geometry/point.hpp b/src/rj_geometry/include/rj_geometry/point.hpp index 63a03f994bf..6ae13ea286d 100644 --- a/src/rj_geometry/include/rj_geometry/point.hpp +++ b/src/rj_geometry/include/rj_geometry/point.hpp @@ -11,7 +11,6 @@ #include #include -#include namespace rj_geometry { @@ -34,10 +33,6 @@ class Point { */ Point(double x = 0, double y = 0) : x_(x), y_(y) {} - /** - * Implicit constructor for creating a Point from a Packet::Point - */ - Point(const Packet::Point& other) : Point(other.x(), other.y()) {} /** * Implicit constructor for creating a Point from a QPointF @@ -69,12 +64,6 @@ class Point { */ [[nodiscard]] QPointF to_q_point_f() const { return QPointF(x(), y()); } - operator Packet::Point() const { - Packet::Point out; - out.set_x(static_cast(x())); - out.set_y(static_cast(y())); - return out; - } /** * does vector addition diff --git a/src/rj_protos/CMakeLists.txt b/src/rj_protos/CMakeLists.txt index 09bf8113f29..452cd778ceb 100644 --- a/src/rj_protos/CMakeLists.txt +++ b/src/rj_protos/CMakeLists.txt @@ -11,16 +11,10 @@ find_package(Protobuf REQUIRED) protobuf_generate_cpp( PROTOBUF_SRCS PROTOBUF_HDRS - protos/Control.proto protos/grSim_Commands.proto protos/grSim_Packet.proto protos/grSim_Replacement.proto - protos/LogFrame.proto - protos/Point.proto - protos/RadioRx.proto - protos/RadioTx.proto protos/referee.proto - protos/Robot.proto protos/ssl_gc_common.proto protos/ssl_gc_geometry.proto protos/ssl_gc_game_event.proto diff --git a/src/rj_protos/protos/Control.proto b/src/rj_protos/protos/Control.proto deleted file mode 100644 index 04ffc484bc4..00000000000 --- a/src/rj_protos/protos/Control.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto2"; -package Packet; - -message Control { - enum ShootMode { - KICK = 0; - CHIP = 1; - } - - enum TriggerMode { - STAND_DOWN = 0; - IMMEDIATE = 1; - ON_BREAK_BEAM = 2; - } - - // LEDs on the robot display different colors based on current role - enum Role { - GOALIE = 0; - DEFENSE = 1; - OFFENSE = 2; - UNKNOWN = 3; - } - - required float xVelocity = 1 [default = 0]; - required float yVelocity = 2 [default = 0]; - required float aVelocity = 3 [default = 0]; - required float dVelocity = 4 [default = 0]; - required uint32 kcStrength = 5 [default = 255]; - required ShootMode shootMode = 6 [default = KICK]; - required TriggerMode triggerMode = 7 [default = STAND_DOWN]; - optional Role role = 9 [default = UNKNOWN]; -} diff --git a/src/rj_protos/protos/LogFrame.proto b/src/rj_protos/protos/LogFrame.proto deleted file mode 100644 index aa224e92e67..00000000000 --- a/src/rj_protos/protos/LogFrame.proto +++ /dev/null @@ -1,169 +0,0 @@ -syntax = "proto2"; -package Packet; - -import "referee.proto"; -import "Point.proto"; -import "RadioTx.proto"; -import "RadioRx.proto"; - -message DebugRobotPath { - message DebugRobotPathPoint { - required Point pos = 2; - required Point vel = 3; - } - - optional sint32 layer = 1 [default = -1]; - repeated DebugRobotPathPoint points = 3; -} - -message DebugPath { - optional uint32 color = 1; - optional sint32 layer = 2 [default = -1]; - repeated Point points = 3; -} - -message DebugCircle { - optional uint32 color = 1; - optional sint32 layer = 2 [default = -1]; - required Point center = 3; - required float radius = 4; -} - -message DebugArc { - optional uint32 color = 1; - optional sint32 layer = 2 [default = -1]; - required Point center = 3; - required float radius = 4; - required float start = 5; - required float end = 6; -} - -message DebugText { - optional uint32 color = 1; - optional sint32 layer = 2 [default = -1]; - optional Point pos = 3; // Not present for robot text, otherwise required - required string text = 4; - optional bool center = 5; -} - -message TestResult { - enum TestState { - INCOMPLETE = 0; - PASSED = 1; - FAILED = 2; - } - optional TestState result = 1; - optional string name = 2; - optional string group = 3; -} - -// Only the first LogFrame in a log file contains this. It contains unchanging -// information about the soccer build and invocation. -message LogConfig { - // Name of the program which generated this log - optional string generator = 1; - - // git commit hash that the generating program was built from - optional string git_version_hash = 2; - - // If true, there were uncommitted changes to the code - optional bool git_version_dirty = 3; - - // If true, we are running in a simulation. - // The standalone loggers don't set this field because they don't know for - // sure. - optional bool simulation = 4; -} - -message LogFrame { - // Only present in the first LogFrame, and not guaranteed even then. - optional LogConfig log_config = 2047; - - // Network packets received since the last iteration - repeated Referee raw_refbox = 27; - repeated RadioRx radio_rx = 3; - - // Deprecated field kept for compatability with old logs - repeated bytes raw_referee = 2; - - // Which team are we playing as? - optional bool blue_team = 4; - - // Time when robot commands are expected to take effect - optional uint64 command_time = 5; - - // Debug graphics - repeated DebugRobotPath debug_robot_paths = 26; - repeated DebugPath debug_paths = 6; - repeated DebugPath debug_polygons = 7; - repeated DebugCircle debug_circles = 8; - repeated DebugArc debug_arcs = 9; - repeated DebugText debug_texts = 10; - repeated string debug_layers = 11; - - // Filtered world state and commands - message Robot { - required Point pos = 1; - required Point world_vel = 7; - optional Point body_vel = 16; - required int32 shell = 2; - required float angle = 3; - optional BallSenseStatus ball_sense_status = 4; - - repeated DebugText text = 6; - - // only during commands - optional Point cmd_vel = 8; - optional float cmd_w = 9; - - optional bool charged = 10; - optional float kicker_voltage = 11; - - repeated MotorStatus motor_status = 12; - - optional bool kicker_works = 13 [default = true]; - optional float battery_voltage = 14; - } - - message Ball { - required Point pos = 1; - required Point vel = 2; - } - - repeated Robot self = 12; - repeated Robot opp = 13; - optional Ball ball = 14; - - // Data sent to the radio - optional RadioTx radio_tx = 15; - - // Which robot is under manual control - optional sint32 manual_id = 16 [default = -1]; - - // True if our goal is on the +X side of vision - optional bool defend_plus_x = 17; - - // Name of the current play - // NOTE: with the transition to a python-based gameplay system, we no longer - // log this. - // Instead, we log the "Behavior Tree", which has the play name and - // all subbehavior names. - optional string play = 18; - - // True if using each half of the field - optional bool use_our_half = 19 [default = true]; - optional bool use_opponent_half = 20 [default = true]; - - // results from testing - repeated TestResult testResults = 21; - - // the description of the behavior tree - // should show the hierarchy of behaviors and each behavior's state - optional string behavior_tree = 22; - - optional string team_name_yellow = 23; - optional string team_name_blue = 24; - - // timestamp in microseconds since epoch - required uint64 timestamp = 25; -} diff --git a/src/rj_protos/protos/Point.proto b/src/rj_protos/protos/Point.proto deleted file mode 100644 index 9eae68734f4..00000000000 --- a/src/rj_protos/protos/Point.proto +++ /dev/null @@ -1,7 +0,0 @@ -syntax = "proto2"; -package Packet; - -message Point { - required float x = 1; - required float y = 2; -} diff --git a/src/rj_protos/protos/RadioRx.proto b/src/rj_protos/protos/RadioRx.proto deleted file mode 100644 index 082af9405c5..00000000000 --- a/src/rj_protos/protos/RadioRx.proto +++ /dev/null @@ -1,52 +0,0 @@ -syntax = "proto2"; -package Packet; - -enum MotorStatus { - Good = 0; - Hall_Failure = 1; - Stalled = 2; - Encoder_Failure = 3; -} - -enum BallSenseStatus { - NoBall = 0; - HasBall = 1; - Dazzled = 2; - Failed = 3; -} - -enum FpgaStatus { - FpgaGood = 0; - FpgaNotInitialized = 1; - FpgaError = 2; -} - -enum HardwareVersion { - Unknown = 0; - RJ2008 = 1; - RJ2011 = 2; - RJ2015 = 3; - RJ2018 = 4; - Simulation = 5; -} - -// Packet going out from radio program to control program -message RadioRx { - required uint64 timestamp = 1; - required uint32 robot_id = 2; - optional float rssi = 3; - optional float battery = 4; - - optional BallSenseStatus ball_sense_status = 5; - - repeated MotorStatus motor_status = 7; - repeated int32 encoders = 8; - - optional uint32 kicker_status = 9; - - optional uint32 kicker_voltage = 11; - - optional FpgaStatus fpga_status = 14 [default = FpgaGood]; - - optional HardwareVersion hardware_version = 12 [default = Unknown]; -} diff --git a/src/rj_protos/protos/RadioTx.proto b/src/rj_protos/protos/RadioTx.proto deleted file mode 100644 index 63633b5c628..00000000000 --- a/src/rj_protos/protos/RadioTx.proto +++ /dev/null @@ -1,8 +0,0 @@ -syntax = "proto2"; -package Packet; - -import "Robot.proto"; - -message RadioTx { - repeated Robot robots = 2; -} diff --git a/src/rj_protos/protos/Robot.proto b/src/rj_protos/protos/Robot.proto deleted file mode 100644 index 74ac8eb096b..00000000000 --- a/src/rj_protos/protos/Robot.proto +++ /dev/null @@ -1,10 +0,0 @@ -syntax="proto2"; -package Packet; - -import "Control.proto"; - -message Robot -{ - required uint32 uid = 1; - required Control control = 3; -} diff --git a/src/rj_radio/src/sim_radio.cpp b/src/rj_radio/src/sim_radio.cpp index 1823cd80890..11e36b360ee 100644 --- a/src/rj_radio/src/sim_radio.cpp +++ b/src/rj_radio/src/sim_radio.cpp @@ -1,7 +1,6 @@ #include "rj_radio/sim_radio.hpp" using namespace std; -using namespace Packet; using namespace boost::asio; namespace radio { diff --git a/src/rj_referee/include/rj_referee/external_referee.hpp b/src/rj_referee/include/rj_referee/external_referee.hpp index 3673b20946e..d0001a5979f 100644 --- a/src/rj_referee/include/rj_referee/external_referee.hpp +++ b/src/rj_referee/include/rj_referee/external_referee.hpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/src/rj_ui/CMakeLists.txt b/src/rj_ui/CMakeLists.txt index 4593f283708..6b3906e6187 100644 --- a/src/rj_ui/CMakeLists.txt +++ b/src/rj_ui/CMakeLists.txt @@ -48,15 +48,12 @@ set(SRC_FILES src/battery_profile.cpp src/battery_widget.cpp src/field_view.cpp - src/log_viewer.cpp src/main_window.cpp src/processor.cpp - src/protobuf_tree.cpp src/referee_tab.cpp src/robot_status_widget.cpp src/robot_widget.cpp src/sim_field_view.cpp - src/strip_chart.cpp src/style_sheet_manager.cpp src/ros2_temp/autonomy_interface.cpp @@ -66,21 +63,17 @@ set(SRC_FILES # QT MOC Headers (need to be included here so qt generates MOC files properly) include/rj_ui/main_window.hpp - include/rj_ui/protobuf_tree.hpp - include/rj_ui/log_viewer.hpp include/rj_ui/referee_tab.hpp include/rj_ui/sim_field_view.hpp # QT UI Files qt/ConfigFileTab.ui - qt/LogViewer.ui qt/MainWindow.ui qt/RefereeTab.ui qt/RobotStatusWidget.ui # QT QRC Files qt/main_icons.qrc - qt/log_icons.qrc ) set(RJ_UI_NODE_AUTOGEN_FILES @@ -90,11 +83,6 @@ set(RJ_UI_NODE_AUTOGEN_FILES qt/RobotStatusWidget.ui ) -set(RJ_UI_LOG_VIEWER_AUTOGEN_FILES - include/rj_ui/log_viewer.hpp - qt/LogViewer.ui -) - set(RJ_UI_DEPS rclcpp Qt5 @@ -129,11 +117,6 @@ add_executable(${PROJECT_NAME}_node ${RJ_UI_NODE_AUTOGEN_FILES} ) -add_executable(log_viewer_node - src/log_viewer_main.cpp - ${RJ_UI_LOG_VIEWER_AUTOGEN_FILES} -) - target_include_directories(${PROJECT_NAME}_node PUBLIC $ @@ -141,13 +124,6 @@ target_include_directories(${PROJECT_NAME}_node ${CMAKE_CURRENT_BINARY_DIR} ) -target_include_directories(log_viewer_node - PUBLIC - $ - $ - ${CMAKE_CURRENT_BINARY_DIR} -) - target_include_directories(${PROJECT_NAME} PUBLIC $ @@ -160,11 +136,6 @@ target_link_libraries(${PROJECT_NAME}_node ${PROJECT_NAME} ) -target_link_libraries(log_viewer_node - PRIVATE - ${PROJECT_NAME} -) - target_link_libraries(${PROJECT_NAME} PUBLIC Boost::boost @@ -185,11 +156,6 @@ ament_target_dependencies(${PROJECT_NAME}_node ${RJ_UI_DEPS} ) -ament_target_dependencies(log_viewer_node - PUBLIC - ${RJ_UI_DEPS} -) - ament_target_dependencies(${PROJECT_NAME} PUBLIC ${RJ_UI_DEPS} @@ -201,7 +167,7 @@ install( ) install( - TARGETS ${PROJECT_NAME}_node log_viewer_node + TARGETS ${PROJECT_NAME}_node DESTINATION lib/${PROJECT_NAME} ) diff --git a/src/rj_ui/include/rj_ui/field_view.hpp b/src/rj_ui/include/rj_ui/field_view.hpp index ede381e27c6..41e7660f185 100644 --- a/src/rj_ui/include/rj_ui/field_view.hpp +++ b/src/rj_ui/include/rj_ui/field_view.hpp @@ -21,9 +21,10 @@ #include #include #include -#include #include +#include "rj_ui/live_frame.hpp" + class Logger; /** class that performs drawing of log data onto the field */ @@ -48,7 +49,7 @@ class FieldView : public QWidget { } } - void history(const std::vector >* value) { + void history(const std::vector >* value) { _history = value; } @@ -78,7 +79,7 @@ class FieldView : public QWidget { void drawText(QPainter& p, QPointF pos, const QString& text, bool center = true) const; - static void drawField(QPainter& p, const Packet::LogFrame* frame); + static void drawField(QPainter& p, const rj_ui::LiveFrame* frame); void drawRobot(QPainter& p, bool blueRobot, int ID, QPointF pos, float theta, bool hasBall = false, bool faulty = false); void drawCoords(QPainter& p); @@ -97,7 +98,7 @@ class FieldView : public QWidget { protected: // Returns a pointer to the most recent frame, or null if none is available. - std::shared_ptr currentFrame(); + std::shared_ptr currentFrame(); // Coordinate transformations rj_geometry::TransformMatrix _screenToWorld; @@ -113,7 +114,7 @@ class FieldView : public QWidget { // How many degrees to rotate text so it shows up the right way on screen int _textRotation{}; - const std::vector >* _history{}; + const std::vector >* _history{}; QVector _layerVisible; }; diff --git a/src/rj_ui/include/rj_ui/live_frame.hpp b/src/rj_ui/include/rj_ui/live_frame.hpp new file mode 100644 index 00000000000..21f4e9a38b3 --- /dev/null +++ b/src/rj_ui/include/rj_ui/live_frame.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace rj_ui { + +enum BallSenseStatus { NoBall, HasBall, Dazzled, Failed }; +enum MotorStatus { Good, Fault }; + +struct DebugPath { + int layer() const { return -1; } + int color() const { return 0; } + int points_size() const { return 0; } + rj_geometry::Point points(int) const { return {}; } +}; +struct DebugRobotPath { + struct DebugRobotPathPoint { + rj_geometry::Point pos() const { return {}; } + rj_geometry::Point vel() const { return {}; } + }; + int layer() const { return -1; } + int points_size() const { return 0; } + DebugRobotPathPoint points(int) const { return {}; } +}; +struct DebugCircle { + int layer() const { return -1; } + int color() const { return 0; } + rj_geometry::Point center() const { return {}; } + float radius() const { return 0; } +}; +struct DebugArc { + int layer() const { return -1; } + int color() const { return 0; } + rj_geometry::Point center() const { return {}; } + float radius() const { return 0; } + float start() const { return 0; } + float end() const { return 0; } +}; +struct DebugText { + int layer() const { return -1; } + int color() const { return 0; } + rj_geometry::Point pos() const { return {}; } + std::string text() const { return {}; } + bool center() const { return true; } +}; + +struct LiveRobot { + int shell() const { return shell_id; } + const rj_geometry::Point& pos() const { return position; } + float angle() const { return static_cast(heading); } + bool has_ball_sense_status() const { return true; } + BallSenseStatus ball_sense_status() const { return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; } + bool has_kicker_works() const { return false; } + bool kicker_works() const { return kicker_ok; } + const std::vector& motor_status() const { return motors; } + MotorStatus motor_status(int index) const { return motors.at(index); } + bool has_battery_voltage() const { return true; } + float battery_voltage() const { return battery; } + const std::vector& text() const { return texts; } + + int shell_id = -1; + rj_geometry::Point position; + double heading = 0; + bool has_ball = false; + bool kicker_ok = true; + float battery = 0; + std::vector motors; + std::vector texts; +}; + +struct LiveBall { + const rj_geometry::Point& pos() const { return position; } + const rj_geometry::Point& vel() const { return velocity; } + rj_geometry::Point position; + rj_geometry::Point velocity; +}; + +struct LiveFrame { + using Robot = LiveRobot; + static LiveFrame from_context(const Context& context) { + LiveFrame frame; + frame.blue = context.blue_team; + frame.defend_plus = context.game_settings.defend_plus_x; + frame.use_our = context.game_settings.use_our_half; + frame.use_opponent = context.game_settings.use_their_half; + frame.manual = context.game_settings.joystick_config.manual_id; + frame.blue_name = context.blue_team ? context.our_info.name : context.their_info.name; + frame.yellow_name = context.blue_team ? context.their_info.name : context.our_info.name; + + for (size_t shell = 0; shell < context.world_state.our_robots.size(); ++shell) { + const auto& state = context.world_state.our_robots[shell]; + if (!state.visible) continue; + LiveRobot robot; + robot.shell_id = static_cast(shell); + robot.position = state.pose.position(); + robot.heading = state.pose.heading(); + const auto& status = context.robot_status[shell]; + robot.has_ball = status.has_ball; + robot.kicker_ok = status.kicker != RobotStatus::KickerState::kFailed; + robot.battery = static_cast(status.battery_voltage); + robot.motors.resize(status.motors_healthy.size(), MotorStatus::Good); + frame.self_.push_back(std::move(robot)); + } + for (size_t shell = 0; shell < context.world_state.their_robots.size(); ++shell) { + const auto& state = context.world_state.their_robots[shell]; + if (!state.visible) continue; + LiveRobot robot; + robot.shell_id = static_cast(shell); + robot.position = state.pose.position(); + robot.heading = state.pose.heading(); + frame.opp_.push_back(std::move(robot)); + } + if (context.world_state.ball.visible) { + frame.ball_state = LiveBall{context.world_state.ball.position, + context.world_state.ball.velocity}; + } + return frame; + } + + bool defend_plus_x() const { return defend_plus; } + bool use_our_half() const { return use_our; } + bool use_opponent_half() const { return use_opponent; } + bool blue_team() const { return blue; } + int manual_id() const { return manual; } + const std::string& team_name_blue() const { return blue_name; } + const std::string& team_name_yellow() const { return yellow_name; } + bool has_ball() const { return ball_state.has_value(); } + const LiveBall& ball() const { return *ball_state; } + const std::vector& debug_paths() const { return debug_paths_; } + const std::vector& debug_robot_paths() const { return debug_robot_paths_; } + const std::vector& debug_circles() const { return debug_circles_; } + const std::vector& debug_arcs() const { return debug_arcs_; } + const std::vector& debug_polygons() const { return debug_polygons_; } + const std::vector& debug_texts() const { return debug_texts_; } + + const std::vector& self_robots() const { return self_; } + const std::vector& opp_robots() const { return opp_; } + const std::vector& self() const { return self_; } + const std::vector& opp() const { return opp_; } + const LiveRobot& self(int index) const { return self_.at(index); } + const LiveRobot& opp(int index) const { return opp_.at(index); } + int self_size() const { return static_cast(self_.size()); } + int opp_size() const { return static_cast(opp_.size()); } + + std::vector self_; + std::vector opp_; + std::optional ball_state; + bool blue = true; + bool defend_plus = false; + bool use_our = true; + bool use_opponent = true; + int manual = -1; + std::string blue_name; + std::string yellow_name; + std::vector debug_paths_; + std::vector debug_robot_paths_; + std::vector debug_circles_; + std::vector debug_arcs_; + std::vector debug_polygons_; + std::vector debug_texts_; +}; + +} // namespace rj_ui diff --git a/src/rj_ui/include/rj_ui/log_viewer.hpp b/src/rj_ui/include/rj_ui/log_viewer.hpp deleted file mode 100644 index 8801ed50890..00000000000 --- a/src/rj_ui/include/rj_ui/log_viewer.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -class LogViewer : public QMainWindow { - Q_OBJECT; - -public: - LogViewer(QWidget* parent = nullptr); - - int frameNumber() const { return roundf(_doubleFrameNumber); } - - void frameNumber(int value) { _doubleFrameNumber = value; } - - // This is called when - bool readFrames(const char* filename); - - std::vector > frames; - -public Q_SLOTS: - void updateViews(); - - void on_actionCoords_toggled(bool state); - - // Field rotation - void on_action0_triggered(); - void on_action90_triggered(); - void on_action180_triggered(); - void on_action270_triggered(); - - void on_timeSlider_sliderPressed(); - void on_timeSlider_sliderMoved(int value); - void on_playbackRate_sliderReleased(); - void on_logBeginning_clicked(); - void on_logPrev_clicked(); - void on_logNext_clicked(); - void on_logEnd_clicked(); - -private: - Ui_LogViewer ui; - - QTimer _updateTimer; - QTime _lastUpdateTime; - double _doubleFrameNumber; - - // Recent history. - // Yeah, it's copied, but if it works in soccer then it works here. - std::vector > _history; - - // Tree items that are not in LogFrame - QTreeWidgetItem* _frameNumberItem; - QTreeWidgetItem* _elapsedTimeItem; -}; diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index ea1c1647c36..4e1eb574da0 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -47,7 +46,6 @@ #include "ui_MainWindow.h" class TestResultTab; -class StripChart; namespace { // Style sheets used for live/non-live controls @@ -74,29 +72,6 @@ class MainWindow : public QMainWindow { /// Selects all debug layers void allDebugOn(); - bool live(); - - void setLive() { - if (!live()) { - _ui.logTree->setStyleSheet(QString("QTreeWidget{%1}").arg(NonLiveStyle)); - _playbackRate = std::nullopt; - } - } - - void setPlayBackRate(double playbackRate) { - if (live()) { - _ui.logTree->setStyleSheet(QString("QTreeWidget{%1}").arg(LiveStyle)); - } - _playbackRate = playbackRate; - } - - int frameNumber() const { return roundf(_doubleFrameNumber); } - - void frameNumber(int value) { _doubleFrameNumber = value; } - - // Call this to update the status bar when the log file has changed - void logFileChanged(); - QTimer updateTimer; void setUseRefChecked(bool use_ref); @@ -150,7 +125,6 @@ private Q_SLOTS: /// Debug menu commands void on_actionRestartUpdateTimer_triggered(); - void on_actionStart_Logging_triggered(); /// Gameplay menu void on_actionSeed_triggered(); @@ -158,17 +132,6 @@ private Q_SLOTS: // Joystick settings void on_joystickKickOnBreakBeam_stateChanged(); - /// Log controls - void on_logHistoryLocation_sliderMoved(int value); - void on_logHistoryLocation_sliderReleased(); - void on_logHistoryLocation_sliderPressed(); - void on_logPlaybackRewind_clicked(); - void on_logPlaybackPrevFrame_clicked(); - void on_logPlaybackPause_clicked(); - void on_logPlaybackNextFrame_clicked(); - void on_logPlaybackPlay_clicked(); - void on_logPlaybackLive_clicked(); - /// Debug layers void on_debugLayers_itemChanged(QListWidgetItem* item); void on_debugLayers_customContextMenuRequested(const QPoint& pos); @@ -234,7 +197,6 @@ private Q_SLOTS: void status(const QString& text, StatusType status); void updateRadioBaseStatus(bool usbRadio); void channel(int n); - void updateDebugLayers(const Packet::LogFrame& frame); Ui_MainWindow _ui{}; const QStandardItemModel* goalieModel{}; @@ -244,16 +206,6 @@ private Q_SLOTS: int current_goalie_num_{0}; - // Log history, copied from Logger. - // This is used by other controls to get log data without having to copy it - // again from the Logger. - std::vector> _history{}; - - // Longer log history, copied from Logger. - // This is used specificially via StripChart and ProtobufTree - // To export a larger amount of data. - std::vector> _longHistory{}; - // Arrays containing dropdown and reset button UI objects std::array robot_pos_selectors{}; std::array position_reset_buttons{}; @@ -273,28 +225,15 @@ private Q_SLOTS: */ void onResetButtonClicked(int robot); - // Tree items that are not in LogFrame - QTreeWidgetItem* _frameNumberItem{}; - QTreeWidgetItem* _elapsedTimeItem{}; - - /// playback rate of the viewer - a value of 1 means realtime - std::optional _playbackRate; - // This is used to update some status items less frequently than the full // field view int _updateCount; - // Tracking fractional frames is the easiest way to allow arbitrary playback - // rates. To keep rounding consistent, only access this with frameNumber(). - double _doubleFrameNumber; - RJ::Time _lastUpdateTime; QLabel* _currentPlay{}; - QLabel* _logFile{}; QLabel* _viewFPS{}; QLabel* _procFPS{}; - QLabel* _logMemory{}; // QActionGroups for Radio Menu Actions std::map qActionGroups{}; @@ -302,9 +241,6 @@ private Q_SLOTS: // maps robot shell IDs to items in the list std::map> _robotStatusItemMap{}; - /// the play, pause, ffwd, etc buttons - std::vector _logPlaybackButtons{}; - std::vector _robotConfigQComboBoxes{}; std::vector _robotDebugResponseQComboBoxes{}; @@ -312,6 +248,8 @@ private Q_SLOTS: std::mutex* context__mutex; Context* context_; + std::vector> _history{}; + // ROS Compatibility stuff void send_quick_command(const PlayState& state); diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index 9379bcece7a..80f8be2c7b3 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -66,7 +64,7 @@ class Processor { RJ::Time last_radio_rx_time; }; - Processor(bool sim, bool blue_team, const std::string& read_log_file = ""); + Processor(bool sim, bool blue_team); virtual ~Processor(); void stop(); @@ -82,13 +80,6 @@ class Processor { float framerate() { return framerate_; } - bool open_log(const QString& filename) { - logger_->write(filename.toStdString()); - return true; - } - - void close_log() { logger_->close(); } - std::lock_guard lock_loop_mutex() { return std::lock_guard(loop_mutex_); } @@ -120,10 +111,6 @@ class Processor { /** Used to start and stop the thread **/ volatile bool running_; - // A logfile to read from. - // When empty, don't read logs at all. - std::string read_log_file_; - // Locked when processing loop stuff is happening (not when blocked for // timing or I/O). This is public so the GUI thread can lock it to access // SystemState, etc. @@ -145,8 +132,6 @@ class Processor { // modules std::shared_ptr gameplay_module_; - std::unique_ptr logger_; - std::shared_ptr ros_executor_; // ROS2 temporary modules diff --git a/src/rj_ui/include/rj_ui/protobuf_tree.hpp b/src/rj_ui/include/rj_ui/protobuf_tree.hpp deleted file mode 100644 index ab8a817ba56..00000000000 --- a/src/rj_ui/include/rj_ui/protobuf_tree.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rj_ui/strip_chart.hpp" - -class QMainWindow; -class QTimer; - -namespace Packet { -class LogFrame; -} - -class ProtobufTree : public QTreeWidget { - Q_OBJECT - -public: - ProtobufTree(QWidget* parent = nullptr); - - // Column numbers - enum { Column_Field = 0, Column_Value = 1, Column_Tag = 2 }; - - // Updates the tree with the given message. - // Returns true if any items were added. - // - // Items will only be removed from the tree when the number of elements - // in a repeated field is reduced. Fields are never removed. - bool message(const google::protobuf::Message& msg); - - void expandMessages(QTreeWidgetItem* item = nullptr); - - // Expands an item recursively - void expandSubtree(QTreeWidgetItem* item); - - // Collapses an item recursively - void collapseSubtree(QTreeWidgetItem* item); - - // This is only used for creating charts - void history(const std::vector >* value) { - _history = value; - } - - QMainWindow* mainWindow; - QTimer* updateTimer; - -protected: - // Recursively updates the tree. This should only be called for items where - // is the item for a message (not a repeated field). - bool addTreeData(QTreeWidgetItem* parent, - const google::protobuf::Message& msg); - - static void addBytes(QTreeWidgetItem* parent, const std::string& bytes); - - virtual void contextMenuEvent(QContextMenuEvent* e) override; - - bool _first; - const std::vector >* _history; -}; diff --git a/src/rj_ui/include/rj_ui/robot_status_widget.hpp b/src/rj_ui/include/rj_ui/robot_status_widget.hpp index 5ef6109ede0..a83a526e34d 100644 --- a/src/rj_ui/include/rj_ui/robot_status_widget.hpp +++ b/src/rj_ui/include/rj_ui/robot_status_widget.hpp @@ -8,7 +8,8 @@ #include #include -#include +#include +#include #include "rj_ui/battery_profile.hpp" #include "ui_RobotStatusWidget.h" @@ -22,10 +23,7 @@ class RobotStatusWidget : public QWidget { public: RobotStatusWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); - void loadFromLogFrame( - const Packet::RadioRx& rx, - const std::optional& maybe_robot, - bool blueTeam); + void load(const RobotStatus& status, const RobotState& robot, bool blueTeam); [[nodiscard]] int shellID() const; void setShellID(int shellID); diff --git a/src/rj_ui/include/rj_ui/strip_chart.hpp b/src/rj_ui/include/rj_ui/strip_chart.hpp deleted file mode 100644 index 56997864602..00000000000 --- a/src/rj_ui/include/rj_ui/strip_chart.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace Packet { -class LogFrame; -} - -// Chart functions: -// -// Gets the value for a given frame. -// Stores the value in v. -// Returns true if the value was available. -// Returns false with v undefined if the value was not available. -namespace Chart { -struct Function { - virtual ~Function() = default; - virtual bool value(const Packet::LogFrame& frame, float* v) const = 0; - - // Vector of tags from LogFrame to the float, double, or point field to be - // used. - // Each tag except the last one must identify a Message. - // A repeated field's tag is followed by the index of the item. - QVector path; - QString name; -}; - -struct PointMagnitude : public Function { - bool value(const Packet::LogFrame& frame, float* v) const override; -}; - -struct NumericField : public Function { - bool value(const Packet::LogFrame& frame, float* v) const override; -}; -} - -class StripChart : public QWidget { -public: - StripChart(QWidget* parent = nullptr); - ~StripChart() override = default; - - void history(const std::vector >* value) { - _history = value; - } - - // Sets the chart function. - // This chart owns the function and will destroy it when needed. - void function(Chart::Function* function); - - QList getFunctions() { return _functions; } - - // Exports the contents of the chart to a .csv file - void exportChart(); - - void minValue(float v) { _minValue = v; } - - void maxValue(float v) { _maxValue = v; } - - void color(const QColor& color) { - _color = color; - update(); - } - - // If true, minValue and maxValue are automatically changed when - // out-of-range values are found - bool autoRange; - - // Arbitrary value for width of the chart, must be <= history size - int chartSize = 1000; - -protected: - void paintEvent(QPaintEvent* e) override; - - // Returns the position for the data at a given frame. - // i is an index in _history, so 0 is the most recent frame - // and increasing indices are older frames. - QPointF dataPoint(int i, float value); - - int indexAtPoint(const QPoint& point); - - // Chart function (see above) - QList _functions; - - float _minValue; - float _maxValue; - QColor _color; - - const std::vector >* _history; - - QPointF _mouse_overlay; -}; diff --git a/src/rj_ui/qt/LogViewer.ui b/src/rj_ui/qt/LogViewer.ui deleted file mode 100644 index 43467d8b987..00000000000 --- a/src/rj_ui/qt/LogViewer.ui +++ /dev/null @@ -1,348 +0,0 @@ - - - LogViewer - - - - 0 - 0 - 800 - 644 - - - - Log Viewer - - - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - - - Playback Speed - - - -600 - - - 600 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 600 - - - - - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Beginning - - - - :/icons/media-skip-backward.png:/icons/media-skip-backward.png - - - - 32 - 32 - - - - true - - - - - - - Previous Frame - - - - :/icons/media-seek-backward.png:/icons/media-seek-backward.png - - - - 32 - 32 - - - - true - - - - - - - Next Frame - - - - :/icons/media-seek-forward.png:/icons/media-seek-forward.png - - - - 32 - 32 - - - - true - - - - - - - End - - - - :/icons/media-skip-forward.png:/icons/media-skip-forward.png - - - - 32 - 32 - - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Time: - - - - - - - Time - - - Qt::Horizontal - - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - 0 - 0 - - - - - - - 0 - 0 - - - - 3 - - - - Field - - - - - Value - - - - - Tag - - - - - - - - - - - 0 - 0 - 800 - 23 - - - - - &View - - - - R&otation - - - - - - - - - - - - - - - true - - - true - - - 0 - - - - - true - - - 90 - - - - - true - - - 180 - - - - - true - - - 270 - - - - - true - - - &Coordinate Frames - - - - - - FieldView - QWidget -
rj_ui/field_view.hpp
- 1 -
- - ProtobufTree - QTreeWidget -
rj_ui/protobuf_tree.hpp
-
-
- - - - - -
diff --git a/src/rj_ui/qt/MainWindow.ui b/src/rj_ui/qt/MainWindow.ui index 6c31282ea29..0f82d36b252 100644 --- a/src/rj_ui/qt/MainWindow.ui +++ b/src/rj_ui/qt/MainWindow.ui @@ -1815,7 +1815,7 @@ 0
- + 0 @@ -3593,11 +3593,6 @@
- - ProtobufTree - QTreeWidget -
rj_ui/protobuf_tree.hpp
-
SimFieldView QWidget @@ -3607,7 +3602,6 @@
- diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index 9e3524cbcd0..2336f30274b 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -21,13 +21,12 @@ #include #include #include -#include #include using namespace std; using namespace boost; -using namespace Packet; +using namespace rj_ui; static QPen redPen(Qt::red, 0); static QPen bluePen(Qt::blue, 0); @@ -82,11 +81,11 @@ void FieldView::mouseMoveEvent(QMouseEvent* me) { _posLabel->setText(s); } -std::shared_ptr FieldView::currentFrame() { +std::shared_ptr FieldView::currentFrame() { if (_history != nullptr && !_history->empty()) { return _history->back(); } - return std::shared_ptr(); + return std::shared_ptr(); } void FieldView::rotate(int value) { @@ -128,7 +127,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { } // Get the latest LogFrame - const std::shared_ptr frame = currentFrame(); + const std::shared_ptr frame = currentFrame(); if (!frame) { // No data available yet @@ -185,7 +184,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { void FieldView::drawWorldSpace(QPainter& p) { // Get the latest LogFrame - const LogFrame* frame = _history->back().get(); + const LiveFrame* frame = _history->back().get(); // Draw the field drawField(p, frame); @@ -194,7 +193,7 @@ void FieldView::drawWorldSpace(QPainter& p) { void FieldView::drawTeamSpace(QPainter& p) { // Get the latest LogFrame - const LogFrame* frame = _history->back().get(); + const LiveFrame* frame = _history->back().get(); if (showTeamNames) { // Draw Team Names @@ -237,7 +236,7 @@ void FieldView::drawTeamSpace(QPainter& p) { int ballTrailLength = 60; for (unsigned int i = _history->size() - std::min(_history->size(), ballTrailLength); i < _history->size(); ++i) { - const LogFrame* oldFrame = _history->at(i).get(); + const LiveFrame* oldFrame = _history->at(i).get(); if (oldFrame != nullptr && oldFrame->has_ball()) { QPointF pos = qpointf(oldFrame->ball().pos()); @@ -375,9 +374,9 @@ void FieldView::drawTeamSpace(QPainter& p) { int pastLocationCount = 40; // number of past locations to show int start = std::max(0, static_cast(_history->size()) - pastLocationCount); for (size_t i = start; i < _history->size(); i++) { - const LogFrame* oldFrame = _history->at(i).get(); + const LiveFrame* oldFrame = _history->at(i).get(); if (oldFrame != nullptr) { - for (const LogFrame::Robot& r : oldFrame->self()) { + for (const LiveFrame::Robot& r : oldFrame->self()) { pair key(1, r.shell()); if (cometTrails.find(key) != cometTrails.end() || i == start) { QPointF pt = qpointf(r.pos()); @@ -389,7 +388,7 @@ void FieldView::drawTeamSpace(QPainter& p) { } } - for (const LogFrame::Robot& r : oldFrame->opp()) { + for (const LiveFrame::Robot& r : oldFrame->opp()) { pair key(2, r.shell()); if (cometTrails.find(key) != cometTrails.end() || i == start) { QPointF pt = qpointf(r.pos()); @@ -421,14 +420,14 @@ void FieldView::drawTeamSpace(QPainter& p) { QPointF rtY = qpointf(rj_geometry::Point(-1, 0).rotated(-_rotate * 90)); // Opponent robots - for (const LogFrame::Robot& r : frame->opp()) { + for (const LiveFrame::Robot& r : frame->opp()) { drawRobot(p, !frame->blue_team(), r.shell(), qpointf(r.pos()), r.angle(), r.ball_sense_status() == HasBall); } // Our robots int manualID = frame->manual_id(); - for (const LogFrame::Robot& r : frame->self()) { + for (const LiveFrame::Robot& r : frame->self()) { QPointF center = qpointf(r.pos()); bool faulty = false; @@ -519,7 +518,7 @@ void FieldView::drawCoords(QPainter& p) { drawText(p, QPointF(0.1, 0.25), "+Y"); } -void FieldView::drawField(QPainter& p, const LogFrame* frame) { +void FieldView::drawField(QPainter& p, const LiveFrame* frame) { p.save(); // reset to center diff --git a/src/rj_ui/src/log_viewer.cpp b/src/rj_ui/src/log_viewer.cpp deleted file mode 100644 index c37c5b5d845..00000000000 --- a/src/rj_ui/src/log_viewer.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; -using namespace boost; -using namespace Packet; -using namespace google::protobuf::io; - -// void usage(const char* prog) { -// fprintf(stderr, "Usage: %s \n", prog); -// exit(1); -// } - -// int main(int argc, char* argv[]) { -// QApplication app(argc, argv); - -// if (argc != 2) { -// usage(argv[0]); -// } - -// LogViewer win; - -// win.readFrames(argv[1]); -// win.showMaximized(); - -// return QApplication::exec(); -// } - -LogViewer::LogViewer(QWidget* parent) : QMainWindow(parent) { - ui.setupUi(this); - - _history.resize(2 * 60); - ui.fieldView->history(&_history); - - _frameNumberItem = new QTreeWidgetItem(ui.tree); - _frameNumberItem->setText(ProtobufTree::Column_Field, "Frame"); - _frameNumberItem->setData(ProtobufTree::Column_Tag, Qt::DisplayRole, -2); - - _elapsedTimeItem = new QTreeWidgetItem(ui.tree); - _elapsedTimeItem->setText(ProtobufTree::Column_Field, "Elapsed Time"); - _elapsedTimeItem->setData(ProtobufTree::Column_Tag, Qt::DisplayRole, -1); - - ui.splitter->setStretchFactor(0, 98); - ui.splitter->setStretchFactor(1, 10); - - QActionGroup* rotateGroup = new QActionGroup(this); - rotateGroup->addAction(ui.action0); - rotateGroup->addAction(ui.action90); - rotateGroup->addAction(ui.action180); - rotateGroup->addAction(ui.action270); - - connect(&_updateTimer, SIGNAL(timeout()), SLOT(updateViews())); - _updateTimer.start(30); -} - -bool LogViewer::readFrames(const char* filename) { - frames.clear(); - ui.timeSlider->setMaximum(0); - - QFile file(filename); - if (!file.open(QFile::ReadOnly)) { - fprintf(stderr, "Can't open %s: %s\n", filename, - (const char*)file.errorString().toLatin1()); - return false; - } - - int n = 0; - while (!file.atEnd()) { - uint32_t size = 0; - if (file.read((char*)&size, sizeof(size)) != sizeof(size)) { - // Broken length - printf("Broken length\n"); - return false; - } - - string str(size, 0); - if (file.read(&str[0], size) != size) { - // Broken packet at end of file - printf("Broken packet\n"); - return false; - } - - std::shared_ptr frame = std::make_shared(); - frames.push_back(frame); - // Parse partial so we can recover from corrupt data - if (!frame->ParsePartialFromString(str)) { - printf("Failed: %s\n", frame->InitializationErrorString().c_str()); - return false; - } - ++n; - } - - ui.timeSlider->setMaximum(frames.size()); - return true; -} - -void LogViewer::updateViews() { - // Update current frame number - QTime time = QTime::currentTime(); - if (!_lastUpdateTime.isNull()) { - _doubleFrameNumber += ui.playbackRate->value() * _lastUpdateTime.msecsTo(time) / 1000.0; - } - _lastUpdateTime = time; - - // Limit to available data - _doubleFrameNumber = max(0.0, _doubleFrameNumber); - _doubleFrameNumber = min(frames.size() - 1.0, _doubleFrameNumber); - - int f = frameNumber(); - const LogFrame& currentFrame = *frames[f]; - - ui.timeSlider->setValue(f); - - // Copy recent history into the FieldView - int n = min(f, (int)_history.size()); - for (int i = 0; i < n; ++i) { - _history[i] = frames[f - i]; - } - for (int i = n; i < (int)_history.size(); ++i) { - _history[i].reset(); - } - - // Update non-message tree items - _frameNumberItem->setData(ProtobufTree::Column_Value, Qt::DisplayRole, frameNumber()); - int elapsedMillis = (currentFrame.command_time() - frames[0]->command_time() + 500) / 1000; - QTime elapsedTime = QTime::fromMSecsSinceStartOfDay(elapsedMillis); - _elapsedTimeItem->setText(ProtobufTree::Column_Value, elapsedTime.toString("hh:mm:ss.zzz")); - - // Sort the tree by tag if items have been added - if (ui.tree->message(currentFrame)) { - // Items have been added, so sort again on tag number - ui.tree->sortItems(ProtobufTree::Column_Tag, Qt::AscendingOrder); - } - - ui.fieldView->update(); -} - -void LogViewer::on_action0_triggered() { ui.fieldView->rotate(0); } - -void LogViewer::on_action90_triggered() { ui.fieldView->rotate(1); } - -void LogViewer::on_action180_triggered() { ui.fieldView->rotate(2); } - -void LogViewer::on_action270_triggered() { ui.fieldView->rotate(3); } - -void LogViewer::on_actionCoords_toggled(bool state) { - ui.fieldView->showCoords = state; - ui.fieldView->update(); -} - -void LogViewer::on_timeSlider_sliderPressed() { ui.playbackRate->setValue(0); } - -void LogViewer::on_timeSlider_sliderMoved(int value) { frameNumber(value); } - -void LogViewer::on_playbackRate_sliderReleased() { - // Center the slider and stop playback - ui.playbackRate->setValue(0); -} - -void LogViewer::on_logNext_clicked() { - ui.playbackRate->setValue(0); - frameNumber(frameNumber() + 1); -} - -void LogViewer::on_logPrev_clicked() { - ui.playbackRate->setValue(0); - frameNumber(frameNumber() - 1); -} - -void LogViewer::on_logBeginning_clicked() { frameNumber(0); } - -void LogViewer::on_logEnd_clicked() { frameNumber(frames.size() - 1); } diff --git a/src/rj_ui/src/log_viewer_main.cpp b/src/rj_ui/src/log_viewer_main.cpp deleted file mode 100644 index cb05d16b39a..00000000000 --- a/src/rj_ui/src/log_viewer_main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; -using namespace boost; -using namespace Packet; -using namespace google::protobuf::io; - -void usage(const char* prog) { - fprintf(stderr, "Usage: %s \n", prog); - exit(1); -} - -int main(int argc, char* argv[]) { - QApplication app(argc, argv); - - if (argc != 2) { - usage(argv[0]); - } - - LogViewer win; - - win.readFrames(argv[1]); - win.showMaximized(); - - return QApplication::exec(); -} \ No newline at end of file diff --git a/src/rj_ui/src/main.cpp b/src/rj_ui/src/main.cpp index 1e139f20b40..9c356147fa6 100644 --- a/src/rj_ui/src/main.cpp +++ b/src/rj_ui/src/main.cpp @@ -32,10 +32,8 @@ void usage(const char* prog) { std::cerr << "\t-s : set random seed (hexadecimal)\n"; std::cerr << "\t-pbk : playbook file name as contained in " "'soccer/gameplay/playbooks/'\n"; - std::cerr << "\t-vlog : view instead of launching normally\n"; std::cerr << "\t-ng: no goalie\n"; std::cerr << "\t-sim: use simulator\n"; - std::cerr << "\t-nolog: don't write log files\n"; std::cerr << "\t-noref: don't use external referee commands\n"; std::cerr << "\t-defend: specify half of field to defend (plus or minus)\n"; std::exit(0); @@ -65,12 +63,10 @@ int main(int argc, char* argv[]) { QString cfg_file; vector play_dirs; bool sim = false; - bool log = true; QString radio_freq; string playbook_file; bool noref = false; bool defend_plus = false; - string read_log_file; for (int i = 1; i < argc; ++i) { const char* var = argv[i]; @@ -87,8 +83,6 @@ int main(int argc, char* argv[]) { blue_team = true; } else if (strcmp(var, "-sim") == 0) { sim = true; - } else if (strcmp(var, "-nolog") == 0) { - log = false; } else if (strcmp(var, "-freq") == 0) { if (i + 1 >= argc) { printf("No radio frequency specified after -freq\n"); @@ -120,13 +114,6 @@ int main(int argc, char* argv[]) { } playbook_file = argv[++i]; - } else if (strcmp(var, "-vlog") == 0) { - if (i + 1 >= argc) { - printf("no log file specified after -vlog\n"); - usage(argv[0]); - } - - read_log_file = argv[++i]; } else if (strcmp(var, "-noref") == 0) { noref = true; } else if (strcmp(var, "-defend") == 0) { @@ -169,7 +156,7 @@ int main(int argc, char* argv[]) { start_global_param_provider("soccer", kGlobalParamServerNode); - auto processor = std::make_unique(sim, blue_team, read_log_file); + auto processor = std::make_unique(sim, blue_team); Context* context = processor->context(); context->game_settings.simulation = sim; @@ -177,28 +164,11 @@ int main(int argc, char* argv[]) { context->game_settings.defend_plus_x = defend_plus; context->game_settings.request_goalie_id = 0; - // If we're reading a log file, we should start off paused. - context->game_settings.paused = !read_log_file.empty(); - auto win = std::make_unique(processor.get(), !noref); win->initialize(); win->setUseRefChecked(!noref); - if (!application_run_directory().exists("./logs")) { - cerr << "No ./run/logs/ directory - not writing log file" << endl; - } else if (!log) { - cerr << "Not writing log file" << endl; - } else if (read_log_file.empty()) { - QString log_file = application_run_directory().filePath("./logs/") + - QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss.log"); - if (!processor->open_log(log_file)) { - printf("Failed to open %s: %m\n", (const char*)log_file.toLatin1()); - } - } - - win->logFileChanged(); - std::thread processor_thread(&Processor::run, processor.get()); while (!processor->is_initialized()) { // Wait until processor finishes initializing diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 1159da0f5b9..53e8b262329 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -49,7 +49,6 @@ using namespace std; using namespace boost; using namespace google::protobuf; -using namespace Packet; using namespace Eigen; constexpr int kHistorySize = 60 * 2; @@ -66,8 +65,7 @@ void calcMinimumWidth(QWidget* widget, const QString& text) { MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* parent) : QMainWindow(parent), - _updateCount(0), - _doubleFrameNumber(-1), + _updateCount(0), _lastUpdateTime(RJ::now()), _processor(processor), context_(processor->context()), @@ -77,19 +75,15 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par qRegisterMetaType>("QVector"); _ui.setupUi(this); - _ui.fieldView->history(&_history); - - _ui.logTree->history(&_longHistory); - _ui.logTree->mainWindow = this; - _ui.logTree->updateTimer = &updateTimer; - - // Initialize live/non-live control styles - - _logFile = new QLabel(this); - _logFile->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); - _logFile->setToolTip("Log File"); - statusBar()->addPermanentWidget(_logFile); - + _ui.logTree->setVisible(false); + _ui.logHistoryLocation->setVisible(false); + _ui.logPlaybackRewind->setVisible(false); + _ui.logPlaybackPrevFrame->setVisible(false); + _ui.logPlaybackPause->setVisible(false); + _ui.logPlaybackNextFrame->setVisible(false); + _ui.logPlaybackPlay->setVisible(false); + _ui.logPlaybackLive->setVisible(false); + _ui.actionStart_Logging->setVisible(false); _viewFPS = new QLabel(this); _viewFPS->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); _viewFPS->setToolTip("Display Framerate"); @@ -102,21 +96,6 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par calcMinimumWidth(_procFPS, "Proc: 00.0 fps"); statusBar()->addPermanentWidget(_procFPS); - _logMemory = new QLabel(this); - _logMemory->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); - _logMemory->setToolTip("Log Memory Usage"); - _logMemory->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - calcMinimumWidth(_logMemory, "Log: 000000/000000 000000 kiB"); - statusBar()->addPermanentWidget(_logMemory); - - _frameNumberItem = new QTreeWidgetItem(_ui.logTree); - _frameNumberItem->setText(ProtobufTree::Column_Field, "Frame"); - _frameNumberItem->setData(ProtobufTree::Column_Tag, Qt::DisplayRole, -2); - - _elapsedTimeItem = new QTreeWidgetItem(_ui.logTree); - _elapsedTimeItem->setText(ProtobufTree::Column_Field, "Elapsed Time"); - _elapsedTimeItem->setData(ProtobufTree::Column_Tag, Qt::DisplayRole, -1); - _ui.debugLayers->setContextMenuPolicy(Qt::CustomContextMenu); QActionGroup* teamGroup = new QActionGroup(this); @@ -157,14 +136,6 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par connect(_ui.manualID, SIGNAL(currentIndexChanged(int)), this, SLOT(on_manualID_currentIndexChanged(int))); - // put all log playback buttons into a vector for easy access later - _logPlaybackButtons.push_back(_ui.logPlaybackRewind); - _logPlaybackButtons.push_back(_ui.logPlaybackPrevFrame); - _logPlaybackButtons.push_back(_ui.logPlaybackPause); - _logPlaybackButtons.push_back(_ui.logPlaybackNextFrame); - _logPlaybackButtons.push_back(_ui.logPlaybackPlay); - _logPlaybackButtons.push_back(_ui.logPlaybackLive); - // Get the item model from the goalieID boxes so we can disable them // properly goalieModel = qobject_cast(_ui.goalieID->model()); @@ -226,8 +197,6 @@ void MainWindow::initialize() { populate_override_position_dropdowns(); - logFileChanged(); - // Initialize to ui defaults on_goalieID_currentIndexChanged(_ui.goalieID->currentIndex()); @@ -252,26 +221,6 @@ void MainWindow::initialize() { _ui.actionDefendMinusX->setChecked(true); } - // If we're reading logs, we should already have some data. Update frames - // for all of it. - for (const auto& frame : context_->logs.frames) { - updateDebugLayers(*frame); - } - - if (context_->logs.state == Logs::State::kReading) { - _playbackRate = 0; - } -} - -void MainWindow::logFileChanged() { - if (context_->logs.state == Logs::State::kWriting) { - QString filename_q = QString::fromStdString(context_->logs.filename.value()); - _logFile->setText(filename_q); - _ui.actionStart_Logging->setText(QString("Already Logging to: ") + filename_q); - _ui.actionStart_Logging->setEnabled(false); - } else { - _logFile->setText("Not Recording"); - } } void MainWindow::addLayer(int i, const QString& name, bool checked) { @@ -321,6 +270,34 @@ void MainWindow::updateFromRefPacket(bool haveExternalReferee) { } void MainWindow::updateViews() { + { + std::lock_guard lock(*context__mutex); + _history.clear(); + _history.push_back(std::make_shared( + rj_ui::LiveFrame::from_context(*context_))); + } + _ui.fieldView->history(&_history); + _ui.fieldView->live = true; + _ui.fieldView->update(); + + ++_updateCount; + if (_updateCount == 4) { + _updateCount = 0; + const RJ::Time now = RJ::now(); + const auto delta = now - _lastUpdateTime; + _lastUpdateTime = now; + _viewFPS->setText(QString("View: %1 fps").arg((RJ::Seconds(1) / delta), 0, 'f', 1)); + _procFPS->setText(QString("Proc: %1 fps").arg(_processor->framerate(), 0, 'f', 1)); + } + + _ui.behaviorTree->setPlainText(QString::fromStdString(context_->behavior_tree)); + _ui.refCommand->setText(QString::fromStdString(context_->play_state.get_human_readout())); + updateStatus(); + updateTimer.start(20); +} + +#if 0 +void MainWindow::updateViews_removed() { // TODO(Kyle): Re-enable manual control #if MANUAL int manual = context_->game_settings.joystick_config.manualID; @@ -631,6 +608,8 @@ void MainWindow::updateViews() { updateTimer.start(20); } +#endif + void MainWindow::updateStatus() { // Guidelines: // Status_Fail is used for severe, usually external, errors such as @@ -749,12 +728,6 @@ void MainWindow::updateStatus() { return; } - if (!sim && context_->logs.state != Logs::State::kWriting) { - // We should record logs during competition - status("NOT RECORDING", StatusType::Status_Warning); - return; - } - status("COMPETITION", StatusType::Status_OK); } @@ -931,6 +904,7 @@ void MainWindow::on_actionRestartUpdateTimer_triggered() { updateTimer.start(30); } +#if 0 void MainWindow::on_actionStart_Logging_triggered() { if (context_->logs.state != Logs::State::kWriting) { if (!QDir("logs").exists()) { @@ -951,24 +925,6 @@ void MainWindow::on_actionStart_Logging_triggered() { // Gameplay commands -void MainWindow::on_actionSeed_triggered() { - QString text = QInputDialog::getText(this, "Set Random Seed", "Hexadecimal seed:"); - if (!text.isNull()) { - long seed = strtol(text.toLatin1(), nullptr, 16); - printf("seed %016lx\n", seed); - srand48(seed); - } -} - -// Joystick settings -void MainWindow::on_joystickKickOnBreakBeam_stateChanged() { -#if MANUAL - std::lock_guard lock(*context__mutex); - context_->game_settings.joystick_config.useKickOnBreakBeam = - _ui.joystickKickOnBreakBeam->checkState() == Qt::CheckState::Checked; -#endif -} - // choose between kick on break beam and immeditate // Log controls @@ -1020,6 +976,25 @@ void MainWindow::on_logPlaybackPlay_clicked() { void MainWindow::on_logPlaybackLive_clicked() { setLive(); } +#endif + +void MainWindow::on_actionSeed_triggered() { + QString text = QInputDialog::getText(this, "Set Random Seed", "Hexadecimal seed:"); + if (!text.isNull()) { + long seed = strtol(text.toLatin1(), nullptr, 16); + printf("seed %016lx\n", seed); + srand48(seed); + } +} + +void MainWindow::on_joystickKickOnBreakBeam_stateChanged() { +#if MANUAL + std::lock_guard lock(*context__mutex); + context_->game_settings.joystick_config.useKickOnBreakBeam = + _ui.joystickKickOnBreakBeam->checkState() == Qt::CheckState::Checked; +#endif +} + void MainWindow::on_actionTeamBlue_triggered() { _ui.team->setText("BLUE"); _ui.team->setStyleSheet("background-color: #4040ff; color: #ffffff"); @@ -1172,7 +1147,8 @@ void MainWindow::on_fastPenaltyYellow_clicked() { queued_command_ = setup_penalty_state.advanced_from_normal_start(); } -bool MainWindow::live() { return !_playbackRate; } +#if 0 +bool MainWindow::live() { return true; } void MainWindow::updateDebugLayers(const LogFrame& frame) { // Check if any debug layers have been added // (layers should never be removed) @@ -1188,6 +1164,7 @@ void MainWindow::updateDebugLayers(const LogFrame& frame) { _ui.debugLayers->sortItems(); } } +#endif /** * The following methods are event listeners for the manual position assignments. diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index 8e951458ffd..2324d9c77e3 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -7,8 +7,7 @@ using namespace google::protobuf; // TODO: Remove this and just use the one in Context. FieldDimensions* current_dimensions = &FieldDimensions::current_dimensions; -Processor::Processor(bool sim, bool blue_team, const std::string& read_log_file) - : read_log_file_(read_log_file), loop_mutex_() { +Processor::Processor(bool /*sim*/, bool /*blue_team*/) : loop_mutex_() { // Set the logger to ros2. rj_utils::set_spdlog_default_ros2("processor"); @@ -20,8 +19,6 @@ Processor::Processor(bool sim, bool blue_team, const std::string& read_log_file) ros_executor_ = std::make_shared(); - logger_ = std::make_unique(&context_); - // ROS2 temp nodes config_client_ = std::make_unique(&context_); referee_sub_ = std::make_unique(&context_, ros_executor_.get()); @@ -34,13 +31,6 @@ Processor::Processor(bool sim, bool blue_team, const std::string& read_log_file) world_state_queue_ = std::make_unique( "world_state_queue", vision_filter::topics::kWorldStateTopic); - if (!read_log_file.empty()) { - logger_->read(read_log_file); - } - - logger_->start(); - - nodes_.push_back(logger_.get()); } Processor::~Processor() { stop(); } @@ -68,8 +58,7 @@ void Processor::run() { // Don't run processor while we're paused or reading logs after the // first cycle (we need to run one because MainWindow waits on a single // cycle of processor to initialize). - while (initialized_ && running_ && - (context_.game_settings.paused || context_.logs.state == Logs::State::kReading)) { + while (initialized_ && running_ && context_.game_settings.paused) { std::this_thread::sleep_for(RJ::Seconds(1.0 / 60.0)); } @@ -119,13 +108,6 @@ void Processor::run() { debug_draw_sub_->run(); - { - loop_mutex()->lock(); - // Log this entire frame - logger_->run(); - loop_mutex()->unlock(); - } - //////////////// // Timing diff --git a/src/rj_ui/src/protobuf_tree.cpp b/src/rj_ui/src/protobuf_tree.cpp deleted file mode 100644 index 82365386053..00000000000 --- a/src/rj_ui/src/protobuf_tree.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include "rj_ui/protobuf_tree.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rj_ui/strip_chart.hpp" - -using namespace std; -using namespace google::protobuf; - -// Map from protobuf field ID to tree item -using FieldMap = QMap; -Q_DECLARE_METATYPE(FieldMap) -Q_DECLARE_METATYPE(const FieldDescriptor*) - -// Roles -enum { - FieldMapRole = Qt::UserRole, // Column_Tag: Holds a FieldMap for this item's children - IsMessageRole, // Column_Tag: true if this item is a message - FieldDescriptorRole // Column_Tag: FieldDescriptor* for this field, if - // applicable -}; - -ProtobufTree::ProtobufTree(QWidget* parent) : QTreeWidget(parent) { - _first = true; - _history = nullptr; - mainWindow = nullptr; - updateTimer = nullptr; -} - -bool ProtobufTree::message(const google::protobuf::Message& msg) { - // Update items - bool ret = addTreeData(invisibleRootItem(), msg); - - // If this was the first time items were added, resize all columns - if (_first && ret) { - _first = false; - - for (int i = 0; i < columnCount(); ++i) { - resizeColumnToContents(i); - } - - setColumnHidden(ProtobufTree::Column_Tag, true); - } - - return ret; -} - -bool ProtobufTree::addTreeData(QTreeWidgetItem* parent, const google::protobuf::Message& msg) { - const Reflection* ref = msg.GetReflection(); - - // Get fields in the message - vector fields; - ref->ListFields(msg, &fields); - - // Get map of field numbers to child items - auto fieldMap = parent->data(Column_Tag, FieldMapRole).value(); - - bool newFields = false; - - // Clear data for missing fields - const Descriptor* desc = msg.GetDescriptor(); - for (FieldMap::const_iterator i = fieldMap.begin(); i != fieldMap.end(); ++i) { - const FieldDescriptor* field = desc->FindFieldByNumber(i.key()); - if (field == nullptr) { - // Field has left the descriptor - should never happen - printf("Lost field %s.%d\n", desc->name().c_str(), i.key()); - continue; - } - - QTreeWidgetItem* item = i.value(); - - bool hasData; - if (field->is_repeated()) { - hasData = (ref->FieldSize(msg, field) != 0); - - if (!hasData && (item->childCount() != 0)) { - // Remove and delete children - for (QTreeWidgetItem* child : item->takeChildren()) { - delete child; - } - } - } else { - hasData = ref->HasField(msg, field); - } - - if (!hasData) { - item->setText(Column_Value, QString()); - item->setData(Column_Value, Qt::CheckStateRole, QVariant()); - } - } - - for (const FieldDescriptor* field : fields) { - // Get the item for this field if the field has been seen before - QTreeWidgetItem* item; - FieldMap::iterator fieldIter = fieldMap.find(field->number()); - if (fieldIter != fieldMap.end()) { - // Field is already in parent - item = *fieldIter; - } else { - // New field - item = new QTreeWidgetItem(parent); - fieldMap.insert(field->number(), item); - - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - parent->setData(Column_Tag, FieldMapRole, QVariant::fromValue(fieldMap)); - item->setData(Column_Tag, Qt::DisplayRole, field->number()); - item->setData(Column_Tag, FieldDescriptorRole, QVariant::fromValue(field)); - item->setText(Column_Field, QString::fromStdString(field->name())); - - if (field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_repeated()) { - // Singular messages are expanded by default - expandItem(item); - } - - newFields = true; - } - - if (field->is_repeated()) { - // Repeated field - int n = ref->FieldSize(msg, field); - - // Show the number of elements as the value for the field itself - item->setData(Column_Value, Qt::DisplayRole, n); - - // Make sure we have enough children - int children = item->childCount(); - if (children < n) { - // Add children - for (int i = children; i < n; ++i) { - auto* child = new QTreeWidgetItem(item); - child->setText(Column_Field, QString("[%1]").arg(i)); - - child->setData(Column_Tag, FieldDescriptorRole, field != nullptr); - - // For repeated items, the tag column holds the index in the - // field - child->setData(Column_Tag, Qt::DisplayRole, i); - - // A FieldMap is not used here because the items don't - // actually have tags. The item's position in its parent is - // its position in the repeated field. - } - - newFields = true; - } else if (children > n) { - // Remove excess children - // Internally, QTreeWidgetItem stores a QList of children. - // Hopefully this is efficient. - QList kids = item->takeChildren(); - for (int i = 0; i < (children - n); ++i) { - delete kids.back(); - kids.pop_back(); - } - item->addChildren(kids); - } - - // Set data for children - for (int i = 0; i < n; ++i) { - QTreeWidgetItem* child = item->child(i); - - switch (field->type()) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - child->setData(Column_Value, Qt::DisplayRole, - ref->GetRepeatedInt32(msg, field, i)); - break; - - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - child->setData(Column_Value, Qt::DisplayRole, - (qlonglong)ref->GetRepeatedInt64(msg, field, i)); - break; - - case FieldDescriptor::TYPE_UINT32: - child->setData(Column_Value, Qt::DisplayRole, - ref->GetRepeatedUInt32(msg, field, i)); - break; - - case FieldDescriptor::TYPE_UINT64: - child->setData(Column_Value, Qt::DisplayRole, - (qulonglong)ref->GetRepeatedUInt64(msg, field, i)); - break; - - case FieldDescriptor::TYPE_FLOAT: - child->setData(Column_Value, Qt::DisplayRole, - ref->GetRepeatedFloat(msg, field, i)); - break; - - case FieldDescriptor::TYPE_DOUBLE: - child->setData(Column_Value, Qt::DisplayRole, - ref->GetRepeatedDouble(msg, field, i)); - break; - - case FieldDescriptor::TYPE_BOOL: - child->setCheckState(Column_Value, ref->GetRepeatedBool(msg, field, i) - ? Qt::Checked - : Qt::Unchecked); - break; - - case FieldDescriptor::TYPE_ENUM: { - const EnumValueDescriptor* ev = ref->GetRepeatedEnum(msg, field, i); - child->setText(Column_Value, QString::fromStdString(ev->name())); - break; - } - - case FieldDescriptor::TYPE_STRING: - child->setText(Column_Value, QString::fromStdString( - ref->GetRepeatedString(msg, field, i))); - break; - - case FieldDescriptor::TYPE_MESSAGE: - child->setData(Column_Tag, IsMessageRole, true); - newFields |= addTreeData(child, ref->GetRepeatedMessage(msg, field, i)); - break; - - case FieldDescriptor::TYPE_BYTES: - addBytes(child, ref->GetRepeatedString(msg, field, i)); - break; - - default: - child->setText(Column_Value, QString("??? %1").arg(field->type())); - break; - } - } - } else { - switch (field->type()) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - item->setData(Column_Value, Qt::DisplayRole, ref->GetInt32(msg, field)); - break; - - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - item->setData(Column_Value, Qt::DisplayRole, - (qlonglong)ref->GetInt64(msg, field)); - break; - - case FieldDescriptor::TYPE_UINT32: - item->setData(Column_Value, Qt::DisplayRole, ref->GetUInt32(msg, field)); - break; - - case FieldDescriptor::TYPE_UINT64: - item->setData(Column_Value, Qt::DisplayRole, - (qulonglong)ref->GetUInt64(msg, field)); - break; - - case FieldDescriptor::TYPE_FLOAT: - item->setData(Column_Value, Qt::DisplayRole, ref->GetFloat(msg, field)); - break; - - case FieldDescriptor::TYPE_DOUBLE: - item->setData(Column_Value, Qt::DisplayRole, ref->GetDouble(msg, field)); - break; - - case FieldDescriptor::TYPE_BOOL: - item->setCheckState(Column_Value, - ref->GetBool(msg, field) ? Qt::Checked : Qt::Unchecked); - break; - - case FieldDescriptor::TYPE_ENUM: { - const EnumValueDescriptor* ev = ref->GetEnum(msg, field); - item->setText(Column_Value, QString::fromStdString(ev->name())); - break; - } - - case FieldDescriptor::TYPE_STRING: - item->setText(Column_Value, QString::fromStdString(ref->GetString(msg, field))); - break; - - case FieldDescriptor::TYPE_MESSAGE: - item->setData(Column_Tag, IsMessageRole, true); - newFields |= addTreeData(item, ref->GetMessage(msg, field)); - break; - - case FieldDescriptor::TYPE_BYTES: - addBytes(item, ref->GetString(msg, field)); - break; - - default: - item->setText(Column_Value, QString("??? %1").arg(field->type())); - break; - } - } - } - - return newFields; -} - -void ProtobufTree::addBytes(QTreeWidgetItem* parent, const std::string& bytes) { - int n = bytes.size(); - parent->setText(Column_Value, QString("%1 bytes").arg(n)); - - int children = parent->childCount(); - if (children < n) { - // Add children - for (int i = children; i < n; ++i) { - auto* child = new QTreeWidgetItem(parent); - child->setText(Column_Field, QString("[%1]").arg(i)); - - // For bytes, the tag column holds the index in the field - child->setData(Column_Tag, Qt::DisplayRole, i); - } - } else if (children > n) { - // Remove children - for (int i = n; i < children; ++i) { - parent->removeChild(parent->child(i)); - } - } - - // Set data - for (int i = 0; i < n; ++i) { - QTreeWidgetItem* item = parent->child(i); - QString text; - text.sprintf("0x%02x", bytes[i]); - item->setText(Column_Value, text); - } -} - -void ProtobufTree::expandMessages(QTreeWidgetItem* item) { - if (item == nullptr) { - item = invisibleRootItem(); - } - - expandItem(item); - - for (int i = 0; i < item->childCount(); ++i) { - QTreeWidgetItem* child = item->child(i); - - if (child->data(Column_Tag, IsMessageRole).toBool()) { - expandMessages(child); - } - } -} - -void ProtobufTree::expandSubtree(QTreeWidgetItem* item) { - expandItem(item); - for (int i = 0; i < item->childCount(); ++i) { - QTreeWidgetItem* child = item->child(i); - expandSubtree(child); - } -} - -void ProtobufTree::collapseSubtree(QTreeWidgetItem* item) { - collapseItem(item); - for (int i = 0; i < item->childCount(); ++i) { - QTreeWidgetItem* child = item->child(i); - collapseSubtree(child); - } -} - -void ProtobufTree::contextMenuEvent(QContextMenuEvent* e) { - QMenu menu; - - QAction *expandItemAction = nullptr, *collapseItemAction = nullptr; - QTreeWidgetItem* item = itemAt(e->pos()); - if (item != nullptr) { - expandItemAction = menu.addAction("Expand"); - collapseItemAction = menu.addAction("Collapse"); - menu.addSeparator(); - } - - QAction* expandMessagesAction = menu.addAction("Expand Only Messages"); - menu.addSeparator(); - - QAction* expandAction = menu.addAction("Expand All"); - QAction* collapseAction = menu.addAction("Collapse All"); - menu.addSeparator(); - - QAction* showTags = menu.addAction("Show tags"); - showTags->setCheckable(true); - showTags->setChecked(!isColumnHidden(Column_Tag)); - - menu.addSeparator(); - - QAction* chartAction = nullptr; - QAction* exportAction = nullptr; - QList chartMenuActions; - - QList dockWidgets; - const FieldDescriptor* field = nullptr; - if ((mainWindow != nullptr) && (item != nullptr)) { - field = item->data(Column_Tag, FieldDescriptorRole).value(); - if (field != nullptr) { - int t = field->type(); - if (t == FieldDescriptor::TYPE_FLOAT || t == FieldDescriptor::TYPE_DOUBLE || - (t == FieldDescriptor::TYPE_MESSAGE && field->message_type()->name() == "Point")) { - dockWidgets = mainWindow->findChildren(); - if (!dockWidgets.isEmpty()) { - QMenu* chartMenu = menu.addMenu("Chart"); - chartAction = chartMenu->addAction("New Chart"); - exportAction = chartMenu->addAction("Export Chart"); - chartMenu->addSeparator(); - for (int i = 0; i < dockWidgets.size(); ++i) { - chartMenuActions.append(chartMenu->addAction( - QString("Add to '%1'").arg(dockWidgets[0]->windowTitle()))); - } - } else { - chartAction = menu.addAction("New Chart"); - } - } - } - } - - QAction* act = menu.exec(mapToGlobal(e->pos())); - if (act == expandMessagesAction) { - collapseAll(); - expandMessages(); - } else if (act == expandAction) { - expandAll(); - } else if (act == collapseAction) { - collapseAll(); - } else if (act == showTags) { - setColumnHidden(Column_Tag, !showTags->isChecked()); - } else if ((expandItemAction != nullptr) && act == expandItemAction) { - expandSubtree(item); - } else if ((collapseItemAction != nullptr) && act == collapseItemAction) { - collapseSubtree(item); - } else if ((chartAction != nullptr) && act == chartAction) { - // Find the path from LogFrame to the chosen item - QVector path; - QStringList names; - for (QTreeWidgetItem* i = item; i != nullptr; i = i->parent()) { - int tag = i->data(Column_Tag, Qt::DisplayRole).toInt(); - path.push_back(tag); - names.append(i->text(Column_Field)); - } - - reverse(path.begin(), path.end()); - reverse(names.begin(), names.end()); - - auto* dock = new QDockWidget(names.join("."), mainWindow); - auto* chart = new StripChart(dock); - chart->history(_history); - - if (field->type() == FieldDescriptor::TYPE_MESSAGE) { - auto* f = new Chart::PointMagnitude; - f->path = path; - f->name = names.join("."); - chart->function(f); - } else { - auto* f = new Chart::NumericField; - f->path = path; - f->name = names.join("."); - chart->function(f); - } - dock->setAttribute(Qt::WA_DeleteOnClose); - dock->setWidget(chart); - mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock); - if (updateTimer != nullptr) { - connect(updateTimer, SIGNAL(timeout()), chart, SLOT(update())); - } - } else if ((exportAction != nullptr) && act == exportAction) { - // If export button was pressed - - auto* chart = new StripChart(); - chart->history(_history); - - // Loop through all open charts and add their data to one chart - for (auto& dockWidget : dockWidgets) { - auto* cChart = dynamic_cast(dockWidget->widget()); - QList functions = cChart->getFunctions(); - for (auto& function : functions) { - chart->function(function); - } - } - - // export that chart - chart->exportChart(); - - } else if (!chartMenuActions.empty()) { - int i = chartMenuActions.indexOf(act); - if (i != -1) { - auto* chart = dynamic_cast(dockWidgets[i]->widget()); - QVector path; - QStringList names; - for (QTreeWidgetItem* i = item; i != nullptr; i = i->parent()) { - int tag = i->data(Column_Tag, Qt::DisplayRole).toInt(); - path.push_back(tag); - names.append(i->text(Column_Field)); - } - - reverse(path.begin(), path.end()); - reverse(names.begin(), names.end()); - - dockWidgets[i]->setWindowTitle(dockWidgets[i]->windowTitle() + ", " + names.join(".")); - chart->history(_history); - - if (field->type() == FieldDescriptor::TYPE_MESSAGE) { - auto* f = new Chart::PointMagnitude; - f->path = path; - f->name = names.join("."); - chart->function(f); - } else { - auto* f = new Chart::NumericField; - f->path = path; - f->name = names.join("."); - chart->function(f); - } - - if (updateTimer != nullptr) { - connect(updateTimer, SIGNAL(timeout()), chart, SLOT(update())); - } - } - } -} diff --git a/src/rj_ui/src/robot_status_widget.cpp b/src/rj_ui/src/robot_status_widget.cpp index 72a6d3a0abd..e6bcfe20a56 100644 --- a/src/rj_ui/src/robot_status_widget.cpp +++ b/src/rj_ui/src/robot_status_widget.cpp @@ -4,26 +4,18 @@ RobotStatusWidget::RobotStatusWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { _ui.setupUi(this); - setBoardID("RJ"); - _shellID = -2; setShellID(-1); - _blueTeam = false; setBlueTeam(true); - _hasRadio = true; setHasRadio(false); - _hasVision = true; setHasVision(false); - _batteryLevel = 1; setBatteryLevel(0.5); - _showstopper = false; - _ui.kickerIndicator->setText(QString("K")); _kickerState = false; setKickerState(false); @@ -34,14 +26,8 @@ int RobotStatusWidget::shellID() const { return _shellID; } void RobotStatusWidget::setShellID(int shellID) { if (shellID != _shellID) { _shellID = shellID; - _ui.robotWidget->setShellID(_shellID); - - if (shellID == -1) { - _ui.shellID->setText(QString("?")); - } else { - _ui.shellID->setText(QString("%1").arg(shellID)); - } + _ui.shellID->setText(shellID == -1 ? QString("?") : QString("%1").arg(shellID)); } } @@ -53,7 +39,6 @@ void RobotStatusWidget::setBlueTeam(bool blueTeam) { } bool RobotStatusWidget::blueTeam() const { return _blueTeam; } - const QString& RobotStatusWidget::boardID() const { return _boardID; } void RobotStatusWidget::setBoardID(const QString& boardID) { @@ -64,29 +49,17 @@ void RobotStatusWidget::setBoardID(const QString& boardID) { } QString RobotStatusWidget::robotModel() const { return _ui.robotModel->text(); } - -void RobotStatusWidget::setRobotModel(const QString& robotModel) { - _ui.robotModel->setText(robotModel); -} - -void RobotStatusWidget::setWheelFault(int wheelIndex, bool faulty) { - _ui.robotWidget->setWheelFault(wheelIndex, faulty); -} - -void RobotStatusWidget::setBallSenseFault(bool faulty) { - _ui.robotWidget->setBallSenseFault(faulty); -} - +void RobotStatusWidget::setRobotModel(const QString& robotModel) { _ui.robotModel->setText(robotModel); } +void RobotStatusWidget::setWheelFault(int wheelIndex, bool faulty) { _ui.robotWidget->setWheelFault(wheelIndex, faulty); } +void RobotStatusWidget::setBallSenseFault(bool faulty) { _ui.robotWidget->setBallSenseFault(faulty); } void RobotStatusWidget::setHasBall(bool hasBall) { _ui.robotWidget->setHasBall(hasBall); } - bool RobotStatusWidget::hasRadio() const { return _hasRadio; } void RobotStatusWidget::setHasRadio(bool hasRadio) { if (hasRadio != _hasRadio) { _hasRadio = hasRadio; - - _ui.radioIndicator->setPixmap(QPixmap( - QString(hasRadio ? ":icons/radio-connected.svg" : ":icons/radio-disconnected.svg"))); + _ui.radioIndicator->setPixmap(QPixmap(QString( + hasRadio ? ":icons/radio-connected.svg" : ":icons/radio-disconnected.svg"))); } } @@ -95,9 +68,8 @@ bool RobotStatusWidget::hasVision() const { return _hasVision; } void RobotStatusWidget::setHasVision(bool hasVision) { if (hasVision != _hasVision) { _hasVision = hasVision; - - _ui.visionIndicator->setPixmap(QPixmap( - QString(hasVision ? ":icons/vision-available.svg" : ":icons/vision-unavailable.svg"))); + _ui.visionIndicator->setPixmap(QPixmap(QString( + hasVision ? ":icons/vision-available.svg" : ":icons/vision-unavailable.svg"))); } } @@ -114,12 +86,8 @@ bool RobotStatusWidget::kickerState() const { return _kickerState; } void RobotStatusWidget::setKickerState(bool kickerState) { _kickerState = kickerState; - - if (kickerState) { - _ui.kickerIndicator->setStyleSheet("QLabel { color : green; }"); - } else { - _ui.kickerIndicator->setStyleSheet("QLabel { color : red; }"); - } + _ui.kickerIndicator->setStyleSheet(kickerState ? "QLabel { color : green; }" + : "QLabel { color : red; }"); } void RobotStatusWidget::setShowstopper(bool showstopper) { @@ -129,141 +97,35 @@ void RobotStatusWidget::setShowstopper(bool showstopper) { } } -void RobotStatusWidget::loadFromLogFrame(const Packet::RadioRx& rx, - const std::optional& maybe_robot, - bool blueTeam) { - // Set shell ID - setShellID(rx.robot_id()); - - // Set team +void RobotStatusWidget::load(const RobotStatus& status, const RobotState& robot, bool blueTeam) { + setShellID(status.shell_id); setBlueTeam(blueTeam); - - // set robot model - QString robotModel; - switch (rx.hardware_version()) { - case Packet::HardwareVersion::RJ2008: - robotModel = "RJ2008"; - break; - case Packet::HardwareVersion::RJ2011: - robotModel = "RJ2011"; - break; - case Packet::HardwareVersion::RJ2015: - robotModel = "RJ2015"; - break; - case Packet::HardwareVersion::RJ2018: - robotModel = "RJ2018"; - break; - case Packet::HardwareVersion::Simulation: - robotModel = "Simulation"; - break; - default: - robotModel = "Unknown Bot"; - } - setRobotModel(robotModel); - - // Radio is always true if we're connected to it... - setHasRadio(true); - - // vision status - bool hasVision = maybe_robot.has_value(); - setHasVision(hasVision); - - // build a list of errors to display in the widget - QStringList errorList; - - // Each motor fault is shown as text in the error text display - // as well as being drawn as a red X on the graphic of a robot - bool hasMotorFault = false; - if (rx.motor_status().size() == 5) { - std::array motorNames = {"FL", "BL", "BR", "FR", "Dribbler"}; - - // Examine status of each motor (including the dribbler) - for (int i = 0; i < 5; ++i) { - bool motorFault = rx.motor_status(i) != Packet::MotorStatus::Good; - - if (motorFault) { - errorList << QString("Motor Fault %1").arg(motorNames[i]); - motorFault = true; - } - - if (i != 4) { - // Show wheel faults (exluding dribbler, which is index 4) - setWheelFault(i, motorFault); - } else { - // Dribbler fault shows up as ball sense fault. - setBallSenseFault(motorFault); - } - - hasMotorFault = hasMotorFault || motorFault; - } - } else { - SPDLOG_ERROR("Expected 5 motors, but only {}.", rx.motor_status_size()); - hasMotorFault = true; - } - - // Kicker - bool kickerFault = true; - bool kickerCharging = false; - if (rx.has_kicker_status()) { - kickerFault = (rx.kicker_status() & Kicker_Enabled) == 0u; - kickerCharging = (rx.kicker_status() & Kicker_Charged) == 0u; - } - if (kickerFault) { - errorList << "Kicker Fault"; - } - setKickerState(kickerCharging); - - // Ball sense - bool ballSenseFault = true; - if (rx.has_ball_sense_status()) { - ballSenseFault = !(rx.ball_sense_status() == Packet::NoBall || - rx.ball_sense_status() == Packet::HasBall); - } - if (ballSenseFault) { - errorList << "Ball Sense Fault"; - } - setBallSenseFault(ballSenseFault); - - // FPGA - bool fpgaWorking = true; - if (rx.has_fpga_status() && rx.fpga_status() != Packet::FpgaGood) { - if (rx.fpga_status() == Packet::FpgaNotInitialized) { - errorList << "FPGA not initialized"; - } else { - errorList << "FPGA error"; - } - fpgaWorking = false; - } - - // Display error text - setErrorText(errorList.join(", ")); - - // Show the ball in the robot's mouth if it has one - bool hasBall = rx.has_ball_sense_status() && rx.ball_sense_status() == Packet::HasBall; - setHasBall(hasBall); - - // Convert battery voltage to a percentage and show it with the battery - // indicator - float batteryLevel = 1; - if (rx.has_battery()) { - if (rx.hardware_version() == Packet::RJ2008 || rx.hardware_version() == Packet::RJ2011) { - batteryLevel = static_cast(kRJ2008BatteryProfile.get_charge_level(rx.battery())); - } else if (rx.hardware_version() == Packet::RJ2015 || - rx.hardware_version() == Packet::RJ2018) { - batteryLevel = static_cast(kRJ2015BatteryProfile.get_charge_level(rx.battery())); - } else if (rx.hardware_version() == Packet::Simulation) { - batteryLevel = 1; - } else { - SPDLOG_ERROR("Unknown hardware revision {}, unable to calculate battery %.", - rx.hardware_version()); - } + setRobotModel(status.version == RobotStatus::HardwareVersion::kSimulated ? "Simulation" : + status.version == RobotStatus::HardwareVersion::kFleet2018 ? "RJ2018" : "Unknown Bot"); + setHasRadio(status.timestamp != RJ::Time{}); + setHasVision(robot.visible); + + QStringList errors; + bool motorFault = false; + for (size_t i = 0; i < status.motors_healthy.size(); ++i) { + const bool faulty = !status.motors_healthy[i]; + motorFault = motorFault || faulty; + if (i < 4) setWheelFault(static_cast(i), faulty); + else setBallSenseFault(faulty); + if (faulty) errors << QString("Motor Fault %1").arg(static_cast(i)); } - setBatteryLevel(batteryLevel); - // If there is an error bad enough that we should get this robot - // off the field, alert the user through the UI that there is a - // "showstopper" - bool showstopper = !hasVision || hasMotorFault || kickerFault || ballSenseFault || - (batteryLevel < 0.25) || !fpgaWorking; - setShowstopper(showstopper); + const bool kickerFault = status.kicker == RobotStatus::KickerState::kFailed; + setKickerState(status.kicker == RobotStatus::KickerState::kCharged); + if (kickerFault) errors << "Kicker Fault"; + setHasBall(status.has_ball); + + const float battery = status.version == RobotStatus::HardwareVersion::kSimulated + ? 1.0f + : static_cast(kRJ2015BatteryProfile.get_charge_level( + status.battery_voltage)); + setBatteryLevel(battery); + setErrorText(errors.join(", ")); + setShowstopper(!robot.visible || motorFault || kickerFault || battery < 0.25f || + !status.fpga_healthy); } diff --git a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp index 43b38673631..9ac132bb02b 100644 --- a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp +++ b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp @@ -35,16 +35,6 @@ void DebugDrawInterface::run() { for (const auto& pose : debug_draw->poses) { // TODO(#1584): Handle poses } - for (const auto& path : debug_draw->paths) { - auto* debug_path = context_->debug_drawer.add_debug_path(); - for (const auto& point : path.points) { - auto* new_point = debug_path->add_points(); - new_point->mutable_pos()->set_x(point.x); - new_point->mutable_pos()->set_y(point.y); - - // TODO(#1584): Use color in trajectory - } - } for (const auto& text : debug_draw->debug_text) { context_->debug_drawer.draw_text( QString::fromStdString(text.text), rj_convert::convert_from_ros(text.position), diff --git a/src/rj_ui/src/sim_field_view.cpp b/src/rj_ui/src/sim_field_view.cpp index 6fdde0179b6..fa3b038debd 100644 --- a/src/rj_ui/src/sim_field_view.cpp +++ b/src/rj_ui/src/sim_field_view.cpp @@ -18,7 +18,6 @@ #include "rj_ui/field_view.hpp" using namespace boost; -using namespace Packet; // Converts from meters to m/s for manually shooting the ball static const float ShootScale = 5; @@ -45,17 +44,17 @@ void SimFieldView::mousePressEvent(QMouseEvent* me) { rj_geometry::Point pos = _worldToTeam * _screenToWorld * me->pos(); - std::shared_ptr frame = currentFrame(); + std::shared_ptr frame = currentFrame(); if (me->button() == Qt::LeftButton && frame) { drag_robot_ = -1; - for (const LogFrame::Robot& r : frame->self()) { + for (const rj_ui::LiveFrame::Robot& r : frame->self()) { if (pos.near_point(r.pos(), kRobotRadius)) { drag_robot_ = r.shell(); drag_robot_blue_ = frame->blue_team(); break; } } - for (const LogFrame::Robot& r : frame->opp()) { + for (const rj_ui::LiveFrame::Robot& r : frame->opp()) { if (pos.near_point(r.pos(), kRobotRadius)) { drag_robot_ = r.shell(); drag_robot_blue_ = !frame->blue_team(); @@ -155,7 +154,7 @@ void SimFieldView::drawTeamSpace(QPainter& p) { FieldView::drawTeamSpace(p); // Simulator drag-to-shoot - std::shared_ptr frame = currentFrame(); + std::shared_ptr frame = currentFrame(); if (drag_mode_ == DRAG_SHOOT && frame) { p.setPen(QPen(Qt::white, 0.025f)); rj_geometry::Point ball = frame->ball().pos(); diff --git a/src/rj_ui/src/strip_chart.cpp b/src/rj_ui/src/strip_chart.cpp deleted file mode 100644 index 6d8c024ee0f..00000000000 --- a/src/rj_ui/src/strip_chart.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include "rj_ui/strip_chart.hpp" - -using namespace std; -using namespace Packet; -using namespace boost; -using namespace google::protobuf; - -StripChart::StripChart(QWidget* /*parent*/) { - _history = nullptr; - _minValue = 0; - _maxValue = 1; - //_function = 0; - autoRange = true; - _color = Qt::yellow; - - QPalette p = palette(); - p.setColor(QPalette::Window, Qt::black); - setPalette(p); - setAutoFillBackground(true); - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - setMinimumSize(100, 100); - - setMouseTracking(true); -} - -void StripChart::function(Chart::Function* function) { - if (function != nullptr) { - _functions.append(function); - } -} - -void StripChart::exportChart() { - QString chartName = QFileDialog::getSaveFileName(this, tr("Save Chart"), "run/newChart.csv", - tr("Csv Files(*.csv)")); - std::ofstream outfile(chartName.toStdString()); - - // output column names - outfile << "Time"; - for (auto* function : _functions) { - outfile << ", " << function->name.toStdString(); - } - outfile << std::endl; - - // output data - - // Get the oldest datapoint to use as the starting time - auto startTime = _history->at(0).get()->timestamp(); - - for (const auto& frame_i : *_history) { - if (frame_i) { - outfile << RJ::timestamp_to_secs(frame_i->timestamp() - startTime); - - for (auto* function : _functions) { - float v = 0; - - if (function->value(*frame_i, &v)) { - outfile << "," << v; - } - } - outfile << std::endl; - } - } - outfile.close(); -} - -QPointF StripChart::dataPoint(int i, float value) { - auto x = static_cast(i * width()) / static_cast(chartSize); - auto h = static_cast(height()); - float y = h - (value - _minValue) * h / (_maxValue - _minValue); - return QPointF(x, y); -} - -int StripChart::indexAtPoint(const QPoint& point) { - return chartSize - 1 - (width() - point.x()) * chartSize / width(); -} - -void StripChart::paintEvent(QPaintEvent* /*e*/) { - if (_history == nullptr || _history->empty() || _functions.isEmpty()) { - return; - } - - QPainter p(this); - - float newMin = _minValue; - float newMax = _maxValue; - - auto mappedCursorPos = mapFromGlobal(QCursor::pos()); - auto highlightedIndex = rect().contains(mappedCursorPos) ? indexAtPoint(mappedCursorPos) : -1; - - auto fontHeight = QFontMetrics(p.font()).height(); - - // X-axis - { - p.setPen(Qt::gray); - QPointF pt = dataPoint(0, 0); - p.drawLine(pt, QPointF(0, pt.y())); - } - - for (int x = 0; x < _functions.size(); x++) { - auto* function = _functions[x]; - - bool haveLast = false; - QPointF last; - if (x == 0) { - p.setPen(_color); - } else { - p.setPen(Qt::red); - } - - int start = 0; - if (chartSize < _history->size()) { - start = static_cast(_history->size()) - chartSize; - } - - for (int i = 0; i < chartSize; ++i) { - float v = 0; - size_t hist_idx = start + i; - if (hist_idx < _history->size() && _history->at(hist_idx) && - function->value(*_history->at(hist_idx).get(), &v)) { - if (autoRange) { - newMin = min(newMin, v); - newMax = max(newMax, v); - } - - QPointF pt = dataPoint(i, v); - - if (i == highlightedIndex) { - p.drawEllipse(pt, 5, 5); - - p.drawText(mappedCursorPos + QPointF(15, 0 + fontHeight * 2 * x), - (" V: " + std::to_string(v)).c_str()); - - if (hist_idx > 0 && hist_idx < _history->size() - 1) { - float v1 = 0; - float v2 = 0; - function->value(*_history->at(hist_idx - 1).get(), &v1); - function->value(*_history->at(hist_idx + 1).get(), &v2); - - auto t1 = _history->at(hist_idx - 1)->timestamp(); - auto t2 = _history->at(hist_idx + 1)->timestamp(); - auto deltaTime = RJ::timestamp_to_secs(t2 - t1); - - auto derivative = (v2 - v1) / (deltaTime); - p.drawText(mappedCursorPos + QPointF(15, fontHeight * (1 + x * 2)), - ("dV: " + std::to_string(derivative)).c_str()); - } - } - - if (haveLast) { - p.drawLine(last, pt); - } - last = pt; - haveLast = true; - } else { - haveLast = false; - } - } - } - - p.drawText(0, height() - 5, std::to_string(newMin).c_str()); - p.drawText(0, fontHeight, std::to_string(newMax).c_str()); - - _minValue = newMin; - _maxValue = newMax; -} - -//////// - -bool Chart::PointMagnitude::value(const Packet::LogFrame& frame, float* v) const { - const Message* msg = &frame; - for (int i = 0; i < path.size(); ++i) { - const Reflection* ref = msg->GetReflection(); - const Descriptor* desc = msg->GetDescriptor(); - - int tag = path[i]; - const FieldDescriptor* fd = desc->FindFieldByNumber(tag); - if (fd->type() != FieldDescriptor::TYPE_MESSAGE) { - SPDLOG_ERROR("Expected a message field."); - return false; - } - - if (fd->is_repeated()) { - ++i; - if (i >= path.size()) { - SPDLOG_ERROR("Ends after tag for repeated field without giving index"); - return false; - } - int j = path[i]; - if (ref->FieldSize(*msg, fd) <= j) { - // Not enough items - return false; - } - msg = &ref->GetRepeatedMessage(*msg, fd, j); - } else { - if (!ref->HasField(*msg, fd)) { - // Missing field - return false; - } - msg = &ref->GetMessage(*msg, fd); - } - } - - if (msg->GetDescriptor()->name() != "Point") { - SPDLOG_ERROR("PointMagnitude: path ended in a message other than Point"); - return false; - } - - *v = static_cast(rj_geometry::Point(*dynamic_cast(msg)).mag()); - return true; -} - -bool Chart::NumericField::value(const Packet::LogFrame& frame, float* v) const { - const Message* msg = &frame; - for (int i = 0; i < path.size(); ++i) { - const Reflection* ref = msg->GetReflection(); - const Descriptor* desc = msg->GetDescriptor(); - - int tag = path[i]; - const FieldDescriptor* fd = desc->FindFieldByNumber(tag); - if (fd->type() != FieldDescriptor::TYPE_MESSAGE) { - if ((i == path.size() - 1 && !fd->is_repeated()) || - (i == path.size() - 2 && fd->is_repeated())) { - // End of the path - if (fd->is_repeated()) { - ++i; - if (i >= path.size()) { - SPDLOG_ERROR( - "NumericField: ends after tag for " - "repeated field without giving index"); - return false; - } - int j = path[i]; - if (ref->FieldSize(*msg, fd) <= j) { - // Not enough items - return false; - } - - switch (fd->type()) { - case FieldDescriptor::TYPE_FLOAT: - *v = ref->GetRepeatedFloat(*msg, fd, j); - break; - - case FieldDescriptor::TYPE_DOUBLE: - *v = static_cast(ref->GetRepeatedDouble(*msg, fd, j)); - break; - - default: - SPDLOG_ERROR( - "NumericField: unsupported repeated " - "field type {}.", - fd->type()); - return false; - } - } else { - switch (fd->type()) { - case FieldDescriptor::TYPE_FLOAT: - *v = ref->GetFloat(*msg, fd); - break; - - case FieldDescriptor::TYPE_DOUBLE: - *v = static_cast(ref->GetDouble(*msg, fd)); - break; - - default: - SPDLOG_ERROR("NumericField: unsupported field type {}", fd->type()); - return false; - } - } - return true; - } - // Non-message field in the middle of a path - SPDLOG_ERROR("NumericField: expected a message field"); - return false; - } - - if (fd->is_repeated()) { - ++i; - if (i >= path.size()) { - SPDLOG_ERROR( - "NumericField: ends after tag for repeated field " - "without giving index"); - return false; - } - int j = path[i]; - if (ref->FieldSize(*msg, fd) <= j) { - // Not enough items - return false; - } - msg = &ref->GetRepeatedMessage(*msg, fd, j); - } else { - if (!ref->HasField(*msg, fd)) { - // Missing field - return false; - } - msg = &ref->GetMessage(*msg, fd); - } - } - - // Not reached - return false; -} diff --git a/src/rj_utils/CMakeLists.txt b/src/rj_utils/CMakeLists.txt index ce211517538..77a035ed116 100644 --- a/src/rj_utils/CMakeLists.txt +++ b/src/rj_utils/CMakeLists.txt @@ -14,6 +14,7 @@ find_package(rclcpp REQUIRED) find_package(rj_msgs REQUIRED) find_package(rj_convert REQUIRED) find_package(rj_protos REQUIRED) +find_package(rj_geometry REQUIRED) find_package(Qt5 COMPONENTS Core Widgets REQUIRED) add_library(${PROJECT_NAME} SHARED @@ -27,6 +28,7 @@ ament_target_dependencies(${PROJECT_NAME} rj_msgs rj_convert rj_protos + rj_geometry ) target_link_libraries(${PROJECT_NAME} diff --git a/src/rj_utils/include/rj_utils/log_utils.hpp b/src/rj_utils/include/rj_utils/log_utils.hpp index e6068d3f384..2640b4e06d6 100644 --- a/src/rj_utils/include/rj_utils/log_utils.hpp +++ b/src/rj_utils/include/rj_utils/log_utils.hpp @@ -1,10 +1,10 @@ #pragma once -#include - #include #include +#include + static inline QColor qcolor(uint32_t value) { uint8_t a = value >> 24; uint8_t r = value >> 16; @@ -13,8 +13,8 @@ static inline QColor qcolor(uint32_t value) { return QColor(r, g, b, a); } -static inline QPointF qpointf(const Packet::Point& pt) { - return QPointF(pt.x(), pt.y()); +static inline QPointF qpointf(const rj_geometry::Point& pt) { + return pt.to_q_point_f(); } static inline uint32_t color(const QColor& color) { diff --git a/src/rj_utils/package.xml b/src/rj_utils/package.xml index 5eeeb1899f0..1ea3cc584ef 100644 --- a/src/rj_utils/package.xml +++ b/src/rj_utils/package.xml @@ -13,6 +13,7 @@ rj_protos rj_convert rj_geometry_msgs + rj_geometry protobuf-dev From a62701bc1f67379747914e2a7cb2e3a1f072912a Mon Sep 17 00:00:00 2001 From: sdhanyamraju6 Date: Wed, 16 Sep 2026 19:32:57 -0400 Subject: [PATCH 03/21] . --- src/rj_common/CMakeLists.txt | 1 + .../include/rj_common/debug_drawer.hpp | 65 ++++++--- .../include/rj_common/debug_drawings.hpp | 98 ++++++++++++++ src/rj_common/src/debug_drawer.cpp | 128 ++++++++++++++++++ src/rj_common/src/planning/trajectory.cpp | 11 ++ src/rj_ui/include/rj_ui/live_frame.hpp | 60 ++++---- src/rj_ui/include/rj_ui/main_window.hpp | 1 + src/rj_ui/src/main_window.cpp | 14 ++ src/rj_ui/src/processor.cpp | 6 +- .../src/ros2_temp/debug_draw_interface.cpp | 9 ++ 10 files changed, 333 insertions(+), 60 deletions(-) create mode 100644 src/rj_common/include/rj_common/debug_drawings.hpp create mode 100644 src/rj_common/src/debug_drawer.cpp diff --git a/src/rj_common/CMakeLists.txt b/src/rj_common/CMakeLists.txt index 632788f67a2..ca3e04a1417 100644 --- a/src/rj_common/CMakeLists.txt +++ b/src/rj_common/CMakeLists.txt @@ -37,6 +37,7 @@ set(RJ_COMMON_DEPS ) add_library(${PROJECT_NAME} SHARED + src/debug_drawer.cpp src/field_dimensions.cpp src/multicast.cpp src/qt_utils.cpp diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 5b814c8f1d7..252381e3297 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -15,6 +16,8 @@ #include #include +#include "rj_common/debug_drawings.hpp" + struct Context; class DebugDrawer { @@ -27,48 +30,64 @@ class DebugDrawer { int find_debug_layer(QString layer); /** @ingroup drawing_functions */ - void draw_polygon(const rj_geometry::Point*, int, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_polygon(const rj_geometry::Point* pts, int n, const QColor& qc = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_polygon(const std::vector&, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_polygon(const std::vector& pts, const QColor& qc = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_polygon(const rj_geometry::Polygon&, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_polygon(const rj_geometry::Polygon& pts, const QColor& qc = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_circle(rj_geometry::Point, float, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_circle(rj_geometry::Point center, float radius, const QColor& qc = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_arc(const rj_geometry::Arc&, const QColor& = Qt::black, - const QString& = QString()) {} + void draw_arc(const rj_geometry::Arc& arc, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_shape(const std::shared_ptr&, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_shape(const std::shared_ptr& obs, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_shape_set(const rj_geometry::ShapeSet&, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_shape_set(const rj_geometry::ShapeSet& shapes, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_line(const rj_geometry::Segment&, const QColor& = Qt::black, - const QString& = QString()) {} + void draw_line(const rj_geometry::Segment& line, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_line(rj_geometry::Point, rj_geometry::Point, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_line(rj_geometry::Point p0, rj_geometry::Point p1, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_text(const QString&, rj_geometry::Point, - const QColor& = Qt::black, const QString& = QString()) {} + void draw_text(const QString& text, rj_geometry::Point pos, const QColor& qw = Qt::black, + const QString& layer = QString()); /** @ingroup drawing_functions */ - void draw_segment(const rj_geometry::Segment&, const QColor& = Qt::black, - const QString& = QString()) {} + void draw_segment(const rj_geometry::Segment& line, const QColor& qw = Qt::black, + const QString& layer = QString()); + + /** + * Helper pass-through method to create a new debug path. + */ + DebugRobotPath& add_debug_path() { return current_.robot_paths.emplace_back(); } + + /** + * Snapshot this cycle's drawings for the UI and start a fresh cycle. + * Layer names are kept so the debug-layer list stays stable. + */ + void commit_frame() { + published_ = std::move(current_); + current_.clear(); + } + + const DebugDrawFrame& published_frame() const { return published_; } private: /// Number of debug layers @@ -82,4 +101,6 @@ class DebugDrawer { Context* context_; + DebugDrawFrame current_; + DebugDrawFrame published_; }; diff --git a/src/rj_common/include/rj_common/debug_drawings.hpp b/src/rj_common/include/rj_common/debug_drawings.hpp new file mode 100644 index 00000000000..ba94ba2df09 --- /dev/null +++ b/src/rj_common/include/rj_common/debug_drawings.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include +#include + +#include + +struct DebugPath { + int layer() const { return layer_; } + uint32_t color() const { return color_; } + int points_size() const { return static_cast(points_.size()); } + const rj_geometry::Point& points(int i) const { return points_.at(i); } + + int layer_ = -1; + uint32_t color_ = 0; + std::vector points_; +}; + +struct DebugRobotPath { + struct DebugRobotPathPoint { + const rj_geometry::Point& pos() const { return pos_; } + const rj_geometry::Point& vel() const { return vel_; } + rj_geometry::Point& mutable_pos() { return pos_; } + rj_geometry::Point& mutable_vel() { return vel_; } + + rj_geometry::Point pos_; + rj_geometry::Point vel_; + }; + + int layer() const { return layer_; } + void set_layer(int layer) { layer_ = layer; } + int points_size() const { return static_cast(points_.size()); } + const DebugRobotPathPoint& points(int i) const { return points_.at(i); } + DebugRobotPathPoint& add_points() { return points_.emplace_back(); } + + int layer_ = -1; + std::vector points_; +}; + +struct DebugCircle { + int layer() const { return layer_; } + uint32_t color() const { return color_; } + const rj_geometry::Point& center() const { return center_; } + float radius() const { return radius_; } + + int layer_ = -1; + uint32_t color_ = 0; + rj_geometry::Point center_; + float radius_ = 0; +}; + +struct DebugArc { + int layer() const { return layer_; } + uint32_t color() const { return color_; } + const rj_geometry::Point& center() const { return center_; } + float radius() const { return radius_; } + float start() const { return start_; } + float end() const { return end_; } + + int layer_ = -1; + uint32_t color_ = 0; + rj_geometry::Point center_; + float radius_ = 0; + float start_ = 0; + float end_ = 0; +}; + +struct DebugText { + int layer() const { return layer_; } + uint32_t color() const { return color_; } + const rj_geometry::Point& pos() const { return pos_; } + const std::string& text() const { return text_; } + bool center() const { return center_; } + + int layer_ = -1; + uint32_t color_ = 0; + rj_geometry::Point pos_; + std::string text_; + bool center_ = true; +}; + +struct DebugDrawFrame { + std::vector paths; + std::vector polygons; + std::vector circles; + std::vector arcs; + std::vector texts; + std::vector robot_paths; + + void clear() { + paths.clear(); + polygons.clear(); + circles.clear(); + arcs.clear(); + texts.clear(); + robot_paths.clear(); + } +}; diff --git a/src/rj_common/src/debug_drawer.cpp b/src/rj_common/src/debug_drawer.cpp new file mode 100644 index 00000000000..96c6bed72dd --- /dev/null +++ b/src/rj_common/src/debug_drawer.cpp @@ -0,0 +1,128 @@ +#include "rj_common/debug_drawer.hpp" + +#include +#include + +int DebugDrawer::find_debug_layer(QString layer) { + if (layer.isNull()) { + layer = "Debug"; + } + + QMap::const_iterator i = debug_layer_map_.find(layer); + if (i == debug_layer_map_.end()) { + // New layer + int n = num_debug_layers_++; + debug_layer_map_[layer] = n; + debug_layers_.append(layer); + return n; + } + // Existing layer + return i.value(); +} + +void DebugDrawer::draw_polygon(const rj_geometry::Point* pts, int n, const QColor& qc, + const QString& layer) { + DebugPath dbg; + dbg.layer_ = find_debug_layer(layer); + dbg.color_ = color(qc); + dbg.points_.reserve(n); + for (int i = 0; i < n; ++i) { + dbg.points_.push_back(pts[i]); + } + current_.polygons.push_back(std::move(dbg)); +} + +void DebugDrawer::draw_polygon(const std::vector& pts, const QColor& qc, + const QString& layer) { + draw_polygon(pts.data(), static_cast(pts.size()), qc, layer); +} + +void DebugDrawer::draw_polygon(const rj_geometry::Polygon& polygon, const QColor& qc, + const QString& layer) { + this->draw_polygon(polygon.vertices, qc, layer); +} + +void DebugDrawer::draw_circle(rj_geometry::Point center, float radius, const QColor& qc, + const QString& layer) { + DebugCircle dbg; + dbg.layer_ = find_debug_layer(layer); + dbg.center_ = center; + dbg.radius_ = radius; + dbg.color_ = color(qc); + current_.circles.push_back(dbg); +} + +void DebugDrawer::draw_arc(const rj_geometry::Arc& arc, const QColor& qc, const QString& layer) { + DebugArc dbg; + dbg.layer_ = find_debug_layer(layer); + dbg.center_ = arc.center(); + dbg.radius_ = static_cast(arc.radius()); + dbg.start_ = static_cast(arc.start()); + dbg.end_ = static_cast(arc.end()); + dbg.color_ = color(qc); + current_.arcs.push_back(dbg); +} + +void DebugDrawer::draw_shape(const std::shared_ptr& obs, const QColor& color, + const QString& layer) { + std::shared_ptr circ_obs = + std::dynamic_pointer_cast(obs); + std::shared_ptr poly_obs = + std::dynamic_pointer_cast(obs); + std::shared_ptr comp_obs = + std::dynamic_pointer_cast(obs); + std::shared_ptr rect_obs = std::dynamic_pointer_cast(obs); + if (circ_obs) { + draw_circle(circ_obs->center, circ_obs->radius(), color, layer); + } else if (poly_obs) { + draw_polygon(poly_obs->vertices, color, layer); + } else if (rect_obs) { + std::vector points = { + rj_geometry::Point{rect_obs->minx(), rect_obs->miny()}, + rj_geometry::Point{rect_obs->maxx(), rect_obs->miny()}, + rj_geometry::Point{rect_obs->maxx(), rect_obs->maxy()}, + rj_geometry::Point{rect_obs->minx(), rect_obs->maxy()}}; + draw_polygon(points.data(), static_cast(points.size()), color, layer); + } else if (comp_obs) { + for (const std::shared_ptr& subshape : comp_obs->subshapes()) { + draw_shape(subshape, color, layer); + } + } +} + +void DebugDrawer::draw_shape_set(const rj_geometry::ShapeSet& shapes, const QColor& color, + const QString& layer) { + for (auto& shape : shapes.shapes()) { + draw_shape(shape, color, layer); + } +} + +void DebugDrawer::draw_line(const rj_geometry::Segment& line, const QColor& qc, + const QString& layer) { + DebugPath dbg; + dbg.layer_ = find_debug_layer(layer); + dbg.points_.push_back(line.pt[0]); + dbg.points_.push_back(line.pt[1]); + dbg.color_ = color(qc); + current_.paths.push_back(std::move(dbg)); +} + +void DebugDrawer::draw_line(rj_geometry::Point p0, rj_geometry::Point p1, const QColor& color, + const QString& layer) { + draw_line(rj_geometry::Segment(p0, p1), color, layer); +} + +void DebugDrawer::draw_text(const QString& text, rj_geometry::Point pos, const QColor& qc, + const QString& layer) { + DebugText dbg; + dbg.layer_ = find_debug_layer(layer); + dbg.text_ = text.toStdString(); + dbg.pos_ = pos; + dbg.color_ = color(qc); + current_.texts.push_back(std::move(dbg)); +} + +void DebugDrawer::draw_segment(const rj_geometry::Segment& line, const QColor& qc, + const QString& layer) { + draw_line(line, qc, layer); +} diff --git a/src/rj_common/src/planning/trajectory.cpp b/src/rj_common/src/planning/trajectory.cpp index 2d1a7049043..1621baf1783 100644 --- a/src/rj_common/src/planning/trajectory.cpp +++ b/src/rj_common/src/planning/trajectory.cpp @@ -183,6 +183,17 @@ Trajectory::Cursor Trajectory::cursor_begin() const { return Cursor{*this, insta void Trajectory::draw(DebugDrawer* drawer, std::optional alt_text_position) const { + if (instants_.size() > 1) { + DebugRobotPath& dbg_path = drawer->add_debug_path(); + dbg_path.set_layer(drawer->find_debug_layer("Motion")); + + for (const RobotInstant& instant : instants_) { + DebugRobotPath::DebugRobotPathPoint& pt = dbg_path.add_points(); + pt.mutable_pos() = instant.pose.position(); + pt.mutable_vel() = instant.velocity.linear(); + } + } + if (debug_text_) { rj_geometry::Point text_pos; diff --git a/src/rj_ui/include/rj_ui/live_frame.hpp b/src/rj_ui/include/rj_ui/live_frame.hpp index 21f4e9a38b3..2b2e16ef5ec 100644 --- a/src/rj_ui/include/rj_ui/live_frame.hpp +++ b/src/rj_ui/include/rj_ui/live_frame.hpp @@ -7,49 +7,19 @@ #include #include +#include namespace rj_ui { +using ::DebugArc; +using ::DebugCircle; +using ::DebugPath; +using ::DebugRobotPath; +using ::DebugText; + enum BallSenseStatus { NoBall, HasBall, Dazzled, Failed }; enum MotorStatus { Good, Fault }; -struct DebugPath { - int layer() const { return -1; } - int color() const { return 0; } - int points_size() const { return 0; } - rj_geometry::Point points(int) const { return {}; } -}; -struct DebugRobotPath { - struct DebugRobotPathPoint { - rj_geometry::Point pos() const { return {}; } - rj_geometry::Point vel() const { return {}; } - }; - int layer() const { return -1; } - int points_size() const { return 0; } - DebugRobotPathPoint points(int) const { return {}; } -}; -struct DebugCircle { - int layer() const { return -1; } - int color() const { return 0; } - rj_geometry::Point center() const { return {}; } - float radius() const { return 0; } -}; -struct DebugArc { - int layer() const { return -1; } - int color() const { return 0; } - rj_geometry::Point center() const { return {}; } - float radius() const { return 0; } - float start() const { return 0; } - float end() const { return 0; } -}; -struct DebugText { - int layer() const { return -1; } - int color() const { return 0; } - rj_geometry::Point pos() const { return {}; } - std::string text() const { return {}; } - bool center() const { return true; } -}; - struct LiveRobot { int shell() const { return shell_id; } const rj_geometry::Point& pos() const { return position; } @@ -120,6 +90,19 @@ struct LiveFrame { frame.ball_state = LiveBall{context.world_state.ball.position, context.world_state.ball.velocity}; } + + const auto& drawings = context.debug_drawer.published_frame(); + frame.debug_paths_ = drawings.paths; + frame.debug_robot_paths_ = drawings.robot_paths; + frame.debug_circles_ = drawings.circles; + frame.debug_arcs_ = drawings.arcs; + frame.debug_polygons_ = drawings.polygons; + frame.debug_texts_ = drawings.texts; + const auto& layers = context.debug_drawer.debug_layers(); + frame.debug_layers_.reserve(layers.size()); + for (const auto& layer : layers) { + frame.debug_layers_.push_back(layer.toStdString()); + } return frame; } @@ -138,6 +121,8 @@ struct LiveFrame { const std::vector& debug_arcs() const { return debug_arcs_; } const std::vector& debug_polygons() const { return debug_polygons_; } const std::vector& debug_texts() const { return debug_texts_; } + int debug_layers_size() const { return static_cast(debug_layers_.size()); } + const std::string& debug_layers(int i) const { return debug_layers_.at(i); } const std::vector& self_robots() const { return self_; } const std::vector& opp_robots() const { return opp_; } @@ -164,6 +149,7 @@ struct LiveFrame { std::vector debug_arcs_; std::vector debug_polygons_; std::vector debug_texts_; + std::vector debug_layers_; }; } // namespace rj_ui diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 4e1eb574da0..7e30e921b13 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -190,6 +190,7 @@ private Q_SLOTS: private: void updateStatus(); void updateFromRefPacket(bool haveExternalReferee); + void updateDebugLayers(const rj_ui::LiveFrame& frame); static std::string formatLabelBold(Side side, const std::string& label); enum class StatusType { Status_OK, Status_Warning, Status_Fail }; diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 53e8b262329..1f3cd3fc15b 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -278,6 +278,7 @@ void MainWindow::updateViews() { } _ui.fieldView->history(&_history); _ui.fieldView->live = true; + updateDebugLayers(*_history.back()); _ui.fieldView->update(); ++_updateCount; @@ -1091,6 +1092,19 @@ void MainWindow::on_debugLayers_itemChanged(QListWidgetItem* item) { _ui.fieldView->update(); } +void MainWindow::updateDebugLayers(const rj_ui::LiveFrame& frame) { + if (frame.debug_layers_size() > _ui.debugLayers->count()) { + for (int i = _ui.debugLayers->count(); i < frame.debug_layers_size(); ++i) { + const QString name = QString::fromStdString(frame.debug_layers(i)); + bool enabled = !std::any_of(defaultHiddenLayers.begin(), defaultHiddenLayers.end(), + [&](const QString& string) { return string == name; }); + addLayer(i, name, enabled); + } + + _ui.debugLayers->sortItems(); + } +} + // NOLINTNEXTLINE(readability-make-member-function-const): this modifies state void MainWindow::setUseRefChecked(bool /* use_ref */) { _ui.actionUse_Field_Oriented_Controls->setChecked(false); diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index 2324d9c77e3..d1435702836 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -106,7 +106,11 @@ void Processor::run() { // Processor Initialization Completed initialized_ = true; - debug_draw_sub_->run(); + { + std::lock_guard lock(loop_mutex_); + debug_draw_sub_->run(); + context_.debug_drawer.commit_frame(); + } //////////////// // Timing diff --git a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp index 9ac132bb02b..8203cd73fa6 100644 --- a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp +++ b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp @@ -34,6 +34,15 @@ void DebugDrawInterface::run() { } for (const auto& pose : debug_draw->poses) { // TODO(#1584): Handle poses + (void)pose; + } + for (const auto& path : debug_draw->paths) { + DebugRobotPath& debug_path = context_->debug_drawer.add_debug_path(); + debug_path.set_layer(context_->debug_drawer.find_debug_layer(QString::fromStdString(layer))); + for (const auto& point : path.points) { + DebugRobotPath::DebugRobotPathPoint& new_point = debug_path.add_points(); + new_point.mutable_pos() = rj_geometry::Point(point.x, point.y); + } } for (const auto& text : debug_draw->debug_text) { context_->debug_drawer.draw_text( From 3d2dc18a8be113c87a06a1825cf2ceae1528c04b Mon Sep 17 00:00:00 2001 From: root Date: Wed, 16 Sep 2026 23:01:13 -0400 Subject: [PATCH 04/21] barely works --- src/rj_common/include/rj_common/context.hpp | 64 +++++ .../include/rj_common/debug_drawings.hpp | 2 + .../include/rj_common/live_frame.hpp | 114 ++++++++ src/rj_ui/include/rj_ui/field_view.hpp | 15 +- src/rj_ui/include/rj_ui/live_frame.hpp | 155 ----------- src/rj_ui/include/rj_ui/main_window.hpp | 4 +- src/rj_ui/include/rj_ui/processor.hpp | 1 + .../include/rj_ui/robot_status_widget.hpp | 3 +- src/rj_ui/src/field_view.cpp | 33 ++- src/rj_ui/src/main_window.cpp | 258 ++---------------- src/rj_ui/src/processor.cpp | 1 + src/rj_ui/src/robot_status_widget.cpp | 6 +- src/rj_ui/src/sim_field_view.cpp | 8 +- 13 files changed, 235 insertions(+), 429 deletions(-) create mode 100644 src/rj_common/include/rj_common/live_frame.hpp delete mode 100644 src/rj_ui/include/rj_ui/live_frame.hpp diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index f98d07cb5b8..944160b07e5 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -15,6 +16,7 @@ #include "rj_common/robot_intent.hpp" #include "rj_common/team_info.hpp" #include "rj_common/world_state.hpp" +#include "rj_common/live_frame.hpp" struct Context { Context() : debug_drawer(this) {} @@ -61,4 +63,66 @@ struct Context { GameSettings game_settings; std::string behavior_tree; + + std::vector> frames; + + RJ::Time start_time; }; + +static std::shared_ptr create_log_frame(const Context& context) { + // Add everything to the log frame. + auto frame = std::make_shared(); + + // Debug drawing + frame->debug_draw_frame = context.debug_drawer.published_frame(); + + frame->blue = context.blue_team; + + // Our robots + for (size_t shell = 0; shell < kNumShells; shell++) { + const auto& state = context.world_state.our_robots.at(shell); + const auto& status = context.robot_status.at(shell); + + if (RJ::now() - status.timestamp < RJ::Seconds(0.5)) { + frame->radio_rx_.push_back(status); + } + + if (!state.visible) { + continue; + } + + rj_common::LiveFrame::fill_robot(&frame->self_.emplace_back(), shell, state, &status); + } + + // Opponent robots + for (size_t shell = 0; shell < kNumShells; shell++) { + const auto& state = context.world_state.their_robots.at(shell); + if (!state.visible) { + continue; + } + + rj_common::LiveFrame::fill_robot(&frame->opp_.emplace_back(), shell, state, nullptr); + } + + // Ball + if (context.world_state.ball.visible) { + frame->ball_state = {context.world_state.ball.position, context.world_state.ball.velocity}; + } + + // Field + frame->manual = context.game_settings.joystick_config.manual_id; + frame->defend_plus = context.game_settings.defend_plus_x; + frame->use_our = context.game_settings.use_our_half; + frame->use_opponent = context.game_settings.use_their_half; + + // Team names + if (context.blue_team) { + frame->yellow_name = context.their_info.name; + frame->blue_name = context.our_info.name; + } else { + frame->yellow_name = context.our_info.name; + frame->blue_name = context.their_info.name; + } + + return frame; +} diff --git a/src/rj_common/include/rj_common/debug_drawings.hpp b/src/rj_common/include/rj_common/debug_drawings.hpp index ba94ba2df09..917bf41a436 100644 --- a/src/rj_common/include/rj_common/debug_drawings.hpp +++ b/src/rj_common/include/rj_common/debug_drawings.hpp @@ -86,6 +86,7 @@ struct DebugDrawFrame { std::vector arcs; std::vector texts; std::vector robot_paths; + std::vector debug_layers; void clear() { paths.clear(); @@ -94,5 +95,6 @@ struct DebugDrawFrame { arcs.clear(); texts.clear(); robot_paths.clear(); + debug_layers.clear(); } }; diff --git a/src/rj_common/include/rj_common/live_frame.hpp b/src/rj_common/include/rj_common/live_frame.hpp new file mode 100644 index 00000000000..f502134dcda --- /dev/null +++ b/src/rj_common/include/rj_common/live_frame.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "rj_common/control/motion_setpoint.hpp" +#include "rj_common/radio/robot_status.hpp" +#include "rj_common/robot_intent.hpp" +#include "rj_common/time.hpp" +#include "rj_common/world_state.hpp" +#include "rj_common/debug_drawings.hpp" +#include "rj_common/radio/robot_status.hpp" + +namespace rj_common { + +enum BallSenseStatus { NoBall, HasBall, Dazzled, Failed }; +enum MotorStatus { Good, Fault }; + +struct LiveRobot { + int shell() const { return shell_id; } + const rj_geometry::Point& pos() const { return position; } + float angle() const { return static_cast(heading); } + bool has_ball_sense_status() const { return true; } + BallSenseStatus ball_sense_status() const { return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; } + bool has_kicker_works() const { return false; } + bool kicker_works() const { return kicker_ok; } + const std::vector& motor_status() const { return motors; } + MotorStatus motor_status(int index) const { return motors.at(index); } + bool has_battery_voltage() const { return true; } + float battery_voltage() const { return battery; } + const std::vector& text() const { return texts; } + + int shell_id = -1; + rj_geometry::Point position; + double heading = 0; + bool has_ball = false; + bool kicker_ok = true; + float battery = 0; + std::vector motors; + std::vector texts; +}; + + +struct LiveBall { + const rj_geometry::Point& pos() const { return position; } + const rj_geometry::Point& vel() const { return velocity; } + rj_geometry::Point position; + rj_geometry::Point velocity; +}; + +struct LiveFrame { + using Robot = LiveRobot; + + bool defend_plus_x() const { return defend_plus; } + bool use_our_half() const { return use_our; } + bool use_opponent_half() const { return use_opponent; } + bool blue_team() const { return blue; } + int manual_id() const { return manual; } + const std::string& team_name_blue() const { return blue_name; } + const std::string& team_name_yellow() const { return yellow_name; } + bool has_ball() const { return ball_state.has_value(); } + const LiveBall& ball() const { return *ball_state; } + const std::vector& debug_paths() const { return debug_draw_frame.paths; } + const std::vector& debug_robot_paths() const { return debug_draw_frame.robot_paths; } + const std::vector& debug_circles() const { return debug_draw_frame.circles; } + const std::vector& debug_arcs() const { return debug_draw_frame.arcs; } + const std::vector& debug_polygons() const { return debug_draw_frame.polygons; } + const std::vector& debug_texts() const { return debug_draw_frame.texts; } + int debug_layers_size() const { return static_cast(debug_draw_frame.debug_layers.size()); } + const std::string& debug_layers(int i) const { return debug_draw_frame.debug_layers.at(i); } + + const std::vector& self() const { return self_; } + const std::vector& opp() const { return opp_; } + const LiveRobot& self(int index) const { return self_.at(index); } + const LiveRobot& opp(int index) const { return opp_.at(index); } + int self_size() const { return static_cast(self_.size()); } + int opp_size() const { return static_cast(opp_.size()); } + + std::vector self_; + std::vector opp_; + std::vector radio_rx_; + std::optional ball_state; + bool blue = true; + bool defend_plus = false; + bool use_our = true; + bool use_opponent = true; + int manual = -1; + std::string blue_name; + std::string yellow_name; + DebugDrawFrame debug_draw_frame; + + static void fill_robot(LiveRobot* out, int shell_id, RobotState const& state, RobotStatus const* status) { + out->shell_id = shell_id; + + out->position = state.pose.position(); + out->heading = state.pose.heading(); + + if (status != nullptr) { + out->has_ball = status->has_ball; + out->motors.resize(5); + for (int i = 0; i < 5; i++) { + out->motors.at(i) = (status->motors_healthy[i] ? MotorStatus::Good + : MotorStatus::Fault); + } + out->kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; + out->battery = static_cast(status->battery_voltage); + } + } +}; + +} // namespace rj_common diff --git a/src/rj_ui/include/rj_ui/field_view.hpp b/src/rj_ui/include/rj_ui/field_view.hpp index 41e7660f185..210c0c1c257 100644 --- a/src/rj_ui/include/rj_ui/field_view.hpp +++ b/src/rj_ui/include/rj_ui/field_view.hpp @@ -17,16 +17,13 @@ #include #include #include +#include #include #include #include #include #include -#include "rj_ui/live_frame.hpp" - -class Logger; - /** class that performs drawing of log data onto the field */ class FieldView : public QWidget { public: @@ -49,7 +46,7 @@ class FieldView : public QWidget { } } - void history(const std::vector >* value) { + void history(const std::vector >* value) { _history = value; } @@ -79,7 +76,7 @@ class FieldView : public QWidget { void drawText(QPainter& p, QPointF pos, const QString& text, bool center = true) const; - static void drawField(QPainter& p, const rj_ui::LiveFrame* frame); + static void drawField(QPainter& p, const rj_common::LiveFrame* frame); void drawRobot(QPainter& p, bool blueRobot, int ID, QPointF pos, float theta, bool hasBall = false, bool faulty = false); void drawCoords(QPainter& p); @@ -98,9 +95,9 @@ class FieldView : public QWidget { protected: // Returns a pointer to the most recent frame, or null if none is available. - std::shared_ptr currentFrame(); + std::shared_ptr currentFrame(); - // Coordinate transformations + // Coordirj_common::LiveFramenate transformations rj_geometry::TransformMatrix _screenToWorld; rj_geometry::TransformMatrix _worldToTeam; rj_geometry::TransformMatrix _teamToWorld; @@ -114,7 +111,7 @@ class FieldView : public QWidget { // How many degrees to rotate text so it shows up the right way on screen int _textRotation{}; - const std::vector >* _history{}; + const std::vector >* _history{}; QVector _layerVisible; }; diff --git a/src/rj_ui/include/rj_ui/live_frame.hpp b/src/rj_ui/include/rj_ui/live_frame.hpp deleted file mode 100644 index 2b2e16ef5ec..00000000000 --- a/src/rj_ui/include/rj_ui/live_frame.hpp +++ /dev/null @@ -1,155 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include - -namespace rj_ui { - -using ::DebugArc; -using ::DebugCircle; -using ::DebugPath; -using ::DebugRobotPath; -using ::DebugText; - -enum BallSenseStatus { NoBall, HasBall, Dazzled, Failed }; -enum MotorStatus { Good, Fault }; - -struct LiveRobot { - int shell() const { return shell_id; } - const rj_geometry::Point& pos() const { return position; } - float angle() const { return static_cast(heading); } - bool has_ball_sense_status() const { return true; } - BallSenseStatus ball_sense_status() const { return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; } - bool has_kicker_works() const { return false; } - bool kicker_works() const { return kicker_ok; } - const std::vector& motor_status() const { return motors; } - MotorStatus motor_status(int index) const { return motors.at(index); } - bool has_battery_voltage() const { return true; } - float battery_voltage() const { return battery; } - const std::vector& text() const { return texts; } - - int shell_id = -1; - rj_geometry::Point position; - double heading = 0; - bool has_ball = false; - bool kicker_ok = true; - float battery = 0; - std::vector motors; - std::vector texts; -}; - -struct LiveBall { - const rj_geometry::Point& pos() const { return position; } - const rj_geometry::Point& vel() const { return velocity; } - rj_geometry::Point position; - rj_geometry::Point velocity; -}; - -struct LiveFrame { - using Robot = LiveRobot; - static LiveFrame from_context(const Context& context) { - LiveFrame frame; - frame.blue = context.blue_team; - frame.defend_plus = context.game_settings.defend_plus_x; - frame.use_our = context.game_settings.use_our_half; - frame.use_opponent = context.game_settings.use_their_half; - frame.manual = context.game_settings.joystick_config.manual_id; - frame.blue_name = context.blue_team ? context.our_info.name : context.their_info.name; - frame.yellow_name = context.blue_team ? context.their_info.name : context.our_info.name; - - for (size_t shell = 0; shell < context.world_state.our_robots.size(); ++shell) { - const auto& state = context.world_state.our_robots[shell]; - if (!state.visible) continue; - LiveRobot robot; - robot.shell_id = static_cast(shell); - robot.position = state.pose.position(); - robot.heading = state.pose.heading(); - const auto& status = context.robot_status[shell]; - robot.has_ball = status.has_ball; - robot.kicker_ok = status.kicker != RobotStatus::KickerState::kFailed; - robot.battery = static_cast(status.battery_voltage); - robot.motors.resize(status.motors_healthy.size(), MotorStatus::Good); - frame.self_.push_back(std::move(robot)); - } - for (size_t shell = 0; shell < context.world_state.their_robots.size(); ++shell) { - const auto& state = context.world_state.their_robots[shell]; - if (!state.visible) continue; - LiveRobot robot; - robot.shell_id = static_cast(shell); - robot.position = state.pose.position(); - robot.heading = state.pose.heading(); - frame.opp_.push_back(std::move(robot)); - } - if (context.world_state.ball.visible) { - frame.ball_state = LiveBall{context.world_state.ball.position, - context.world_state.ball.velocity}; - } - - const auto& drawings = context.debug_drawer.published_frame(); - frame.debug_paths_ = drawings.paths; - frame.debug_robot_paths_ = drawings.robot_paths; - frame.debug_circles_ = drawings.circles; - frame.debug_arcs_ = drawings.arcs; - frame.debug_polygons_ = drawings.polygons; - frame.debug_texts_ = drawings.texts; - const auto& layers = context.debug_drawer.debug_layers(); - frame.debug_layers_.reserve(layers.size()); - for (const auto& layer : layers) { - frame.debug_layers_.push_back(layer.toStdString()); - } - return frame; - } - - bool defend_plus_x() const { return defend_plus; } - bool use_our_half() const { return use_our; } - bool use_opponent_half() const { return use_opponent; } - bool blue_team() const { return blue; } - int manual_id() const { return manual; } - const std::string& team_name_blue() const { return blue_name; } - const std::string& team_name_yellow() const { return yellow_name; } - bool has_ball() const { return ball_state.has_value(); } - const LiveBall& ball() const { return *ball_state; } - const std::vector& debug_paths() const { return debug_paths_; } - const std::vector& debug_robot_paths() const { return debug_robot_paths_; } - const std::vector& debug_circles() const { return debug_circles_; } - const std::vector& debug_arcs() const { return debug_arcs_; } - const std::vector& debug_polygons() const { return debug_polygons_; } - const std::vector& debug_texts() const { return debug_texts_; } - int debug_layers_size() const { return static_cast(debug_layers_.size()); } - const std::string& debug_layers(int i) const { return debug_layers_.at(i); } - - const std::vector& self_robots() const { return self_; } - const std::vector& opp_robots() const { return opp_; } - const std::vector& self() const { return self_; } - const std::vector& opp() const { return opp_; } - const LiveRobot& self(int index) const { return self_.at(index); } - const LiveRobot& opp(int index) const { return opp_.at(index); } - int self_size() const { return static_cast(self_.size()); } - int opp_size() const { return static_cast(opp_.size()); } - - std::vector self_; - std::vector opp_; - std::optional ball_state; - bool blue = true; - bool defend_plus = false; - bool use_our = true; - bool use_opponent = true; - int manual = -1; - std::string blue_name; - std::string yellow_name; - std::vector debug_paths_; - std::vector debug_robot_paths_; - std::vector debug_circles_; - std::vector debug_arcs_; - std::vector debug_polygons_; - std::vector debug_texts_; - std::vector debug_layers_; -}; - -} // namespace rj_ui diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 7e30e921b13..6a58d4bf51f 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -190,7 +190,7 @@ private Q_SLOTS: private: void updateStatus(); void updateFromRefPacket(bool haveExternalReferee); - void updateDebugLayers(const rj_ui::LiveFrame& frame); + void updateDebugLayers(const rj_common::LiveFrame& frame); static std::string formatLabelBold(Side side, const std::string& label); enum class StatusType { Status_OK, Status_Warning, Status_Fail }; @@ -249,7 +249,7 @@ private Q_SLOTS: std::mutex* context__mutex; Context* context_; - std::vector> _history{}; + std::vector> _history{}; // ROS Compatibility stuff void send_quick_command(const PlayState& state); diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index 80f8be2c7b3..f47c4fb2d45 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/src/rj_ui/include/rj_ui/robot_status_widget.hpp b/src/rj_ui/include/rj_ui/robot_status_widget.hpp index a83a526e34d..9db679b272b 100644 --- a/src/rj_ui/include/rj_ui/robot_status_widget.hpp +++ b/src/rj_ui/include/rj_ui/robot_status_widget.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include "rj_ui/battery_profile.hpp" @@ -23,7 +24,7 @@ class RobotStatusWidget : public QWidget { public: RobotStatusWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); - void load(const RobotStatus& status, const RobotState& robot, bool blueTeam); + void load(const RobotStatus& status, const std::optional& maybe_robot, bool blueTeam); [[nodiscard]] int shellID() const; void setShellID(int shellID); diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index 2336f30274b..7d2a9bc14b6 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -26,7 +26,6 @@ using namespace std; using namespace boost; -using namespace rj_ui; static QPen redPen(Qt::red, 0); static QPen bluePen(Qt::blue, 0); @@ -81,11 +80,11 @@ void FieldView::mouseMoveEvent(QMouseEvent* me) { _posLabel->setText(s); } -std::shared_ptr FieldView::currentFrame() { +std::shared_ptr FieldView::currentFrame() { if (_history != nullptr && !_history->empty()) { return _history->back(); } - return std::shared_ptr(); + return std::shared_ptr(); } void FieldView::rotate(int value) { @@ -127,7 +126,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { } // Get the latest LogFrame - const std::shared_ptr frame = currentFrame(); + const std::shared_ptr frame = currentFrame(); if (!frame) { // No data available yet @@ -184,7 +183,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { void FieldView::drawWorldSpace(QPainter& p) { // Get the latest LogFrame - const LiveFrame* frame = _history->back().get(); + const rj_common::LiveFrame* frame = _history->back().get(); // Draw the field drawField(p, frame); @@ -193,7 +192,7 @@ void FieldView::drawWorldSpace(QPainter& p) { void FieldView::drawTeamSpace(QPainter& p) { // Get the latest LogFrame - const LiveFrame* frame = _history->back().get(); + const rj_common::LiveFrame* frame = _history->back().get(); if (showTeamNames) { // Draw Team Names @@ -236,7 +235,7 @@ void FieldView::drawTeamSpace(QPainter& p) { int ballTrailLength = 60; for (unsigned int i = _history->size() - std::min(_history->size(), ballTrailLength); i < _history->size(); ++i) { - const LiveFrame* oldFrame = _history->at(i).get(); + const rj_common::LiveFrame* oldFrame = _history->at(i).get(); if (oldFrame != nullptr && oldFrame->has_ball()) { QPointF pos = qpointf(oldFrame->ball().pos()); @@ -374,9 +373,9 @@ void FieldView::drawTeamSpace(QPainter& p) { int pastLocationCount = 40; // number of past locations to show int start = std::max(0, static_cast(_history->size()) - pastLocationCount); for (size_t i = start; i < _history->size(); i++) { - const LiveFrame* oldFrame = _history->at(i).get(); + const rj_common::LiveFrame* oldFrame = _history->at(i).get(); if (oldFrame != nullptr) { - for (const LiveFrame::Robot& r : oldFrame->self()) { + for (const rj_common::LiveFrame::Robot& r : oldFrame->self()) { pair key(1, r.shell()); if (cometTrails.find(key) != cometTrails.end() || i == start) { QPointF pt = qpointf(r.pos()); @@ -388,7 +387,7 @@ void FieldView::drawTeamSpace(QPainter& p) { } } - for (const LiveFrame::Robot& r : oldFrame->opp()) { + for (const rj_common::LiveFrame::Robot& r : oldFrame->opp()) { pair key(2, r.shell()); if (cometTrails.find(key) != cometTrails.end() || i == start) { QPointF pt = qpointf(r.pos()); @@ -420,26 +419,26 @@ void FieldView::drawTeamSpace(QPainter& p) { QPointF rtY = qpointf(rj_geometry::Point(-1, 0).rotated(-_rotate * 90)); // Opponent robots - for (const LiveFrame::Robot& r : frame->opp()) { + for (const rj_common::LiveFrame::Robot& r : frame->opp()) { drawRobot(p, !frame->blue_team(), r.shell(), qpointf(r.pos()), r.angle(), - r.ball_sense_status() == HasBall); + r.ball_sense_status() == rj_common::HasBall); } // Our robots int manualID = frame->manual_id(); - for (const LiveFrame::Robot& r : frame->self()) { + for (const rj_common::LiveFrame::Robot& r : frame->self()) { QPointF center = qpointf(r.pos()); bool faulty = false; if (r.has_ball_sense_status() && - (r.ball_sense_status() == Dazzled || r.ball_sense_status() == Failed)) { + (r.ball_sense_status() == rj_common::Dazzled || r.ball_sense_status() == rj_common::Failed)) { faulty = true; } if (r.has_kicker_works() && !r.kicker_works()) { // faulty = true; } for (int i = 0; i < r.motor_status().size(); ++i) { - if (r.motor_status(i) != Good) { + if (r.motor_status(i) != rj_common::Good) { faulty = true; } } @@ -448,7 +447,7 @@ void FieldView::drawTeamSpace(QPainter& p) { } drawRobot(p, frame->blue_team(), r.shell(), center, r.angle(), - r.ball_sense_status() == HasBall, faulty); + r.ball_sense_status() == rj_common::HasBall, faulty); // Highlight the manually controlled robot if (manualID == r.shell()) { @@ -518,7 +517,7 @@ void FieldView::drawCoords(QPainter& p) { drawText(p, QPointF(0.1, 0.25), "+Y"); } -void FieldView::drawField(QPainter& p, const LiveFrame* frame) { +void FieldView::drawField(QPainter& p, const rj_common::LiveFrame* frame) { p.save(); // reset to center diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 1f3cd3fc15b..1a4e7d3f386 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -51,8 +51,7 @@ using namespace boost; using namespace google::protobuf; using namespace Eigen; -constexpr int kHistorySize = 60 * 2; -constexpr int kLongHistorySize = 60 * 60 * 30; +constexpr size_t kHistorySize = 60 * 2; static const std::vector defaultHiddenLayers{ "MotionControl", "Global Obstacles", "Local Obstacles", "Planning0", "Planning1", @@ -75,6 +74,8 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par qRegisterMetaType>("QVector"); _ui.setupUi(this); + _ui.fieldView->history(&_history); + _ui.logTree->setVisible(false); _ui.logHistoryLocation->setVisible(false); _ui.logPlaybackRewind->setVisible(false); @@ -270,35 +271,6 @@ void MainWindow::updateFromRefPacket(bool haveExternalReferee) { } void MainWindow::updateViews() { - { - std::lock_guard lock(*context__mutex); - _history.clear(); - _history.push_back(std::make_shared( - rj_ui::LiveFrame::from_context(*context_))); - } - _ui.fieldView->history(&_history); - _ui.fieldView->live = true; - updateDebugLayers(*_history.back()); - _ui.fieldView->update(); - - ++_updateCount; - if (_updateCount == 4) { - _updateCount = 0; - const RJ::Time now = RJ::now(); - const auto delta = now - _lastUpdateTime; - _lastUpdateTime = now; - _viewFPS->setText(QString("View: %1 fps").arg((RJ::Seconds(1) / delta), 0, 'f', 1)); - _procFPS->setText(QString("Proc: %1 fps").arg(_processor->framerate(), 0, 'f', 1)); - } - - _ui.behaviorTree->setPlainText(QString::fromStdString(context_->behavior_tree)); - _ui.refCommand->setText(QString::fromStdString(context_->play_state.get_human_readout())); - updateStatus(); - updateTimer.start(20); -} - -#if 0 -void MainWindow::updateViews_removed() { // TODO(Kyle): Re-enable manual control #if MANUAL int manual = context_->game_settings.joystick_config.manualID; @@ -343,134 +315,39 @@ void MainWindow::updateViews_removed() { _viewFPS->setText(QString("View: %1 fps").arg(framerate, 0, 'f', 1)); _procFPS->setText(QString("Proc: %1 fps").arg(_processor->framerate(), 0, 'f', 1)); - - _logMemory->setText( - QString("Log: %1 kiB").arg(QString::number((context_->logs.size_bytes + 512) / 1024))); } auto value = _ui.logHistoryLocation->value(); - std::shared_ptr live_frame; - RJ::Time start_time; - int minFrame = 0; - int maxFrame = 0; + std::shared_ptr live_frame; // Grab frames { std::lock_guard lock(*context__mutex); - if (context_->logs.frames.empty()) { + if (context_->frames.empty()) { // No log frames, nothing else to update. return; } - start_time = context_->logs.start_time; - - size_t num_dropped = context_->logs.dropped_frames; - - if (live()) { - _doubleFrameNumber = static_cast(context_->logs.frames.size() + num_dropped); - } else { - _doubleFrameNumber += *_playbackRate; - } - - minFrame = num_dropped; - maxFrame = static_cast(num_dropped + context_->logs.frames.size()) - 1; - - if (_doubleFrameNumber < minFrame) { - _doubleFrameNumber = minFrame; - } else if (_doubleFrameNumber >= maxFrame) { - _doubleFrameNumber = maxFrame; - setLive(); - } - - _ui.logHistoryLocation->setMinimum(minFrame); - _ui.logHistoryLocation->setMaximum(maxFrame); - - live_frame = context_->logs.frames.back(); - - // Cast to ints so that subtraction doesn't overflow. - int start = std::max(frameNumber() - kLongHistorySize, minFrame); - - // Read the latest frames - _longHistory.assign(context_->logs.frames.begin() + start - num_dropped, - context_->logs.frames.begin() + frameNumber() - num_dropped + 1); + live_frame = context_->frames.back(); } - // Set the history vector by taking the last kHistorySize elements of the - // "long" history, or fewer if _longHistory is shorter. - _history.assign( - _longHistory.end() - std::min(kHistorySize, static_cast(_longHistory.size())), - _longHistory.end()); + // // Set the history vector by taking the last kHistorySize elements of the + // // "long" history, or fewer if _longHistory is shorter. + _history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), context_->frames.end()); // Update field view _ui.fieldView->update(); - /**************************************************************************/ - /***************** Update the history/playback interface ******************/ - /**************************************************************************/ - _ui.logHistoryLocation->setTickInterval(60 * 60); // interval is ~ 1 minute - _ui.logHistoryLocation->setValue(static_cast(_doubleFrameNumber)); - - // enable playback buttons based on playback rate - for (QPushButton* playbackBtn : _logPlaybackButtons) { - playbackBtn->setEnabled(true); - } - _ui.logPlaybackLive->setEnabled(!live()); - - if (live() || abs(*_playbackRate) > 0.01) { - _ui.logPlaybackPause->setAutoFillBackground(false); - } else { - _ui.logPlaybackPause->setAutoFillBackground(true); - } - - // enable previous frame button based on position in the log - _ui.logPlaybackPrevFrame->setEnabled(_doubleFrameNumber >= 1); - _ui.logPlaybackNextFrame->setEnabled(!live()); - // Update status indicator updateStatus(); - update_cache(_game_settings.paused, !live(), &_game_settings_valid); - // Check if any debug layers have been added // (layers should never be removed) if (live_frame) { updateDebugLayers(*live_frame); } - // Get the frame at the log playback time - const std::shared_ptr currentFrame = _history.back(); - - // Update the playback labels - if (currentFrame) { - auto gametime = RJ::Time(chrono::microseconds(currentFrame->timestamp())) - start_time; - auto minutes = chrono::duration_cast(gametime); - gametime -= minutes; - auto seconds = chrono::duration_cast(gametime); - gametime -= seconds; - auto deciseconds = chrono::duration_cast>>(gametime); - - _ui.logTime->setText(QString::fromStdString(to_string(minutes.count()) + ":" + - to_string(seconds.count()) + "." + - to_string(deciseconds.count()))); - - _ui.frameNumLabel->setText( - QString("%1/%2").arg(QString::number(frameNumber())).arg(QString::number(maxFrame))); - } - - /**************************************************************************/ - /***************** Update log tree and behavior tree **********************/ - /**************************************************************************/ - if (currentFrame != nullptr) { - _ui.logTree->message(*currentFrame); - - // update the behavior tree view - QString behaviorStr = QString::fromStdString(currentFrame->behavior_tree()); - if (_ui.behaviorTree->toPlainText() != behaviorStr) { - _ui.behaviorTree->setPlainText(behaviorStr); - } - } - /**************************************************************************/ /******************** Update referee information **************************/ /**************************************************************************/ @@ -513,23 +390,23 @@ void MainWindow::updateViews_removed() { /**************************************************************************/ /********************** Update robot status list **************************/ /**************************************************************************/ - if (currentFrame != nullptr) { + if (live_frame != nullptr) { // update robot status list for (size_t shell = 0; shell < kNumShells; shell++) { // Search for the corresponding references. - auto maybe_rx = [&]() -> std::optional> { - for (int i = 0; i < currentFrame->radio_rx_size(); i++) { - if (currentFrame->radio_rx(i).robot_id() == shell) { - return currentFrame->radio_rx(i); + auto maybe_rx = [&]() -> std::optional> { + for (auto & i : live_frame->radio_rx_) { + if (i.shell_id == shell) { + return i; } } return std::nullopt; }(); auto maybe_robot = - [&]() -> std::optional> { - for (int i = 0; i < currentFrame->self_size(); i++) { - if (currentFrame->self(i).shell() == shell) { - return currentFrame->self(i); + [&]() -> std::optional> { + for (int i = 0; i < live_frame->self_size(); i++) { + if (live_frame->self(i).shell() == shell) { + return live_frame->self(i); } } return std::nullopt; @@ -583,7 +460,7 @@ void MainWindow::updateViews_removed() { } if (statusWidget != nullptr) { - statusWidget->loadFromLogFrame(rx, maybe_robot, currentFrame->blue_team()); + statusWidget->load(rx, maybe_robot, live_frame->blue_team()); } } } @@ -609,8 +486,6 @@ void MainWindow::updateViews_removed() { updateTimer.start(20); } -#endif - void MainWindow::updateStatus() { // Guidelines: // Status_Fail is used for severe, usually external, errors such as @@ -905,80 +780,6 @@ void MainWindow::on_actionRestartUpdateTimer_triggered() { updateTimer.start(30); } -#if 0 -void MainWindow::on_actionStart_Logging_triggered() { - if (context_->logs.state != Logs::State::kWriting) { - if (!QDir("logs").exists()) { - QDir().mkdir("logs"); - } - - QString logFile = - QString("logs/") + QDateTime::currentDateTime().toString("yyyyMMdd-hhmmss.log"); - - if (!_processor->open_log(logFile)) { - printf("Failed to open %s: %m\n", (const char*)logFile.toLatin1()); - } else { - _ui.actionStart_Logging->setText(QString("Now Logging to:") + logFile); - _ui.actionStart_Logging->setEnabled(false); - } - } -} - -// Gameplay commands - -// choose between kick on break beam and immeditate - -// Log controls -void MainWindow::on_logHistoryLocation_sliderMoved(int value) { - // Sync frameNumber with logHistory slider - _doubleFrameNumber = value; - - // pause playback - setPlayBackRate(0); -} - -void MainWindow::on_logHistoryLocation_sliderPressed() { - on_logHistoryLocation_sliderMoved(_ui.logHistoryLocation->value()); -} - -void MainWindow::on_logHistoryLocation_sliderReleased() { on_logHistoryLocation_sliderPressed(); } - -void MainWindow::on_logPlaybackRewind_clicked() { - if (live()) { - setPlayBackRate(-1); - } else { - *_playbackRate += -0.5; - } -} - -void MainWindow::on_logPlaybackPrevFrame_clicked() { - setPlayBackRate(0); - _doubleFrameNumber -= 1; -} - -void MainWindow::on_logPlaybackPause_clicked() { - if (live() || std::abs(*_playbackRate) > 0.1) { - setPlayBackRate(0); - } else { - setPlayBackRate(1); - } -} - -void MainWindow::on_logPlaybackNextFrame_clicked() { - setPlayBackRate(0); - _doubleFrameNumber += 1; -} - -void MainWindow::on_logPlaybackPlay_clicked() { - if (!live()) { - *_playbackRate += 0.5; - } -} - -void MainWindow::on_logPlaybackLive_clicked() { setLive(); } - -#endif - void MainWindow::on_actionSeed_triggered() { QString text = QInputDialog::getText(this, "Set Random Seed", "Hexadecimal seed:"); if (!text.isNull()) { @@ -1092,7 +893,7 @@ void MainWindow::on_debugLayers_itemChanged(QListWidgetItem* item) { _ui.fieldView->update(); } -void MainWindow::updateDebugLayers(const rj_ui::LiveFrame& frame) { +void MainWindow::updateDebugLayers(const rj_common::LiveFrame& frame) { if (frame.debug_layers_size() > _ui.debugLayers->count()) { for (int i = _ui.debugLayers->count(); i < frame.debug_layers_size(); ++i) { const QString name = QString::fromStdString(frame.debug_layers(i)); @@ -1161,25 +962,6 @@ void MainWindow::on_fastPenaltyYellow_clicked() { queued_command_ = setup_penalty_state.advanced_from_normal_start(); } -#if 0 -bool MainWindow::live() { return true; } -void MainWindow::updateDebugLayers(const LogFrame& frame) { - // Check if any debug layers have been added - // (layers should never be removed) - if (frame.debug_layers_size() > _ui.debugLayers->count()) { - // Add the missing layers and turn them on - for (int i = _ui.debugLayers->count(); i < frame.debug_layers_size(); ++i) { - const QString name = QString::fromStdString(frame.debug_layers(i)); - bool enabled = !std::any_of(defaultHiddenLayers.begin(), defaultHiddenLayers.end(), - [&](const QString& string) { return string == name; }); - addLayer(i, name, enabled); - } - - _ui.debugLayers->sortItems(); - } -} -#endif - /** * The following methods are event listeners for the manual position assignments. * In the QT5 event handling system, these methods are automatically connected to the diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index d1435702836..813a7d3e9e7 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -110,6 +110,7 @@ void Processor::run() { std::lock_guard lock(loop_mutex_); debug_draw_sub_->run(); context_.debug_drawer.commit_frame(); + context_.frames.emplace_back(create_log_frame(context_)); } //////////////// diff --git a/src/rj_ui/src/robot_status_widget.cpp b/src/rj_ui/src/robot_status_widget.cpp index e6bcfe20a56..eb9b26e1263 100644 --- a/src/rj_ui/src/robot_status_widget.cpp +++ b/src/rj_ui/src/robot_status_widget.cpp @@ -97,13 +97,13 @@ void RobotStatusWidget::setShowstopper(bool showstopper) { } } -void RobotStatusWidget::load(const RobotStatus& status, const RobotState& robot, bool blueTeam) { +void RobotStatusWidget::load(const RobotStatus& status, const std::optional& maybe_robot, bool blueTeam) { setShellID(status.shell_id); setBlueTeam(blueTeam); setRobotModel(status.version == RobotStatus::HardwareVersion::kSimulated ? "Simulation" : status.version == RobotStatus::HardwareVersion::kFleet2018 ? "RJ2018" : "Unknown Bot"); setHasRadio(status.timestamp != RJ::Time{}); - setHasVision(robot.visible); + setHasVision(maybe_robot.has_value()); QStringList errors; bool motorFault = false; @@ -126,6 +126,6 @@ void RobotStatusWidget::load(const RobotStatus& status, const RobotState& robot, status.battery_voltage)); setBatteryLevel(battery); setErrorText(errors.join(", ")); - setShowstopper(!robot.visible || motorFault || kickerFault || battery < 0.25f || + setShowstopper(!maybe_robot.has_value() || motorFault || kickerFault || battery < 0.25f || !status.fpga_healthy); } diff --git a/src/rj_ui/src/sim_field_view.cpp b/src/rj_ui/src/sim_field_view.cpp index fa3b038debd..e470a47293e 100644 --- a/src/rj_ui/src/sim_field_view.cpp +++ b/src/rj_ui/src/sim_field_view.cpp @@ -44,17 +44,17 @@ void SimFieldView::mousePressEvent(QMouseEvent* me) { rj_geometry::Point pos = _worldToTeam * _screenToWorld * me->pos(); - std::shared_ptr frame = currentFrame(); + std::shared_ptr frame = currentFrame(); if (me->button() == Qt::LeftButton && frame) { drag_robot_ = -1; - for (const rj_ui::LiveFrame::Robot& r : frame->self()) { + for (const rj_common::LiveFrame::Robot& r : frame->self()) { if (pos.near_point(r.pos(), kRobotRadius)) { drag_robot_ = r.shell(); drag_robot_blue_ = frame->blue_team(); break; } } - for (const rj_ui::LiveFrame::Robot& r : frame->opp()) { + for (const rj_common::LiveFrame::Robot& r : frame->opp()) { if (pos.near_point(r.pos(), kRobotRadius)) { drag_robot_ = r.shell(); drag_robot_blue_ = !frame->blue_team(); @@ -154,7 +154,7 @@ void SimFieldView::drawTeamSpace(QPainter& p) { FieldView::drawTeamSpace(p); // Simulator drag-to-shoot - std::shared_ptr frame = currentFrame(); + std::shared_ptr frame = currentFrame(); if (drag_mode_ == DRAG_SHOOT && frame) { p.setPen(QPen(Qt::white, 0.025f)); rj_geometry::Point ball = frame->ball().pos(); From 2d6becf16f648212f90a8a19bd2ed610037bf920 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 16 Sep 2026 23:30:14 -0400 Subject: [PATCH 05/21] holy i think this works --- src/rj_common/include/rj_common/debug_drawer.hpp | 5 ++++- src/rj_common/include/rj_common/debug_drawings.hpp | 4 ++-- src/rj_common/include/rj_common/live_frame.hpp | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 252381e3297..596600aaac0 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -84,7 +84,10 @@ class DebugDrawer { */ void commit_frame() { published_ = std::move(current_); - current_.clear(); + current_.clear(); + for (const QString& string : debug_layers_) { + current_.debug_layers_.push_back(string.toStdString()); + } } const DebugDrawFrame& published_frame() const { return published_; } diff --git a/src/rj_common/include/rj_common/debug_drawings.hpp b/src/rj_common/include/rj_common/debug_drawings.hpp index 917bf41a436..d6cc23bc1a0 100644 --- a/src/rj_common/include/rj_common/debug_drawings.hpp +++ b/src/rj_common/include/rj_common/debug_drawings.hpp @@ -86,7 +86,7 @@ struct DebugDrawFrame { std::vector arcs; std::vector texts; std::vector robot_paths; - std::vector debug_layers; + std::vector debug_layers_; void clear() { paths.clear(); @@ -95,6 +95,6 @@ struct DebugDrawFrame { arcs.clear(); texts.clear(); robot_paths.clear(); - debug_layers.clear(); + debug_layers_.clear(); } }; diff --git a/src/rj_common/include/rj_common/live_frame.hpp b/src/rj_common/include/rj_common/live_frame.hpp index f502134dcda..1e9f928a062 100644 --- a/src/rj_common/include/rj_common/live_frame.hpp +++ b/src/rj_common/include/rj_common/live_frame.hpp @@ -69,8 +69,8 @@ struct LiveFrame { const std::vector& debug_arcs() const { return debug_draw_frame.arcs; } const std::vector& debug_polygons() const { return debug_draw_frame.polygons; } const std::vector& debug_texts() const { return debug_draw_frame.texts; } - int debug_layers_size() const { return static_cast(debug_draw_frame.debug_layers.size()); } - const std::string& debug_layers(int i) const { return debug_draw_frame.debug_layers.at(i); } + int debug_layers_size() const { return static_cast(debug_draw_frame.debug_layers_.size()); } + const std::string& debug_layers(int i) const { return debug_draw_frame.debug_layers_.at(i); } const std::vector& self() const { return self_; } const std::vector& opp() const { return opp_; } From 8c70f3a4860e3ce3cd97c9cde8cb02516dc85a1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 23:32:03 -0400 Subject: [PATCH 06/21] Fix Code Style On sd/rm-logger (#2559) automated style fixes Co-authored-by: sanatd33 --- src/rj_common/include/rj_common/context.hpp | 2 +- .../include/rj_common/debug_drawer.hpp | 2 +- .../include/rj_common/live_frame.hpp | 27 +++++++----- src/rj_ui/include/rj_ui/field_view.hpp | 2 +- src/rj_ui/include/rj_ui/processor.hpp | 2 +- .../include/rj_ui/robot_status_widget.hpp | 7 +-- src/rj_ui/src/field_view.cpp | 4 +- src/rj_ui/src/main_window.cpp | 9 ++-- src/rj_ui/src/processor.cpp | 1 - src/rj_ui/src/robot_status_widget.cpp | 43 ++++++++++++------- .../src/ros2_temp/debug_draw_interface.cpp | 3 +- src/rj_utils/include/rj_utils/log_utils.hpp | 4 +- 12 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 944160b07e5..abbd71eb829 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -10,13 +10,13 @@ #include "rj_common/debug_drawer.hpp" #include "rj_common/game_settings.hpp" #include "rj_common/game_state.hpp" +#include "rj_common/live_frame.hpp" #include "rj_common/planning/robot_constraints.hpp" #include "rj_common/planning/trajectory.hpp" #include "rj_common/radio/robot_status.hpp" #include "rj_common/robot_intent.hpp" #include "rj_common/team_info.hpp" #include "rj_common/world_state.hpp" -#include "rj_common/live_frame.hpp" struct Context { Context() : debug_drawer(this) {} diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 596600aaac0..0d7728efc99 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -84,7 +84,7 @@ class DebugDrawer { */ void commit_frame() { published_ = std::move(current_); - current_.clear(); + current_.clear(); for (const QString& string : debug_layers_) { current_.debug_layers_.push_back(string.toStdString()); } diff --git a/src/rj_common/include/rj_common/live_frame.hpp b/src/rj_common/include/rj_common/live_frame.hpp index 1e9f928a062..36aa5e67fae 100644 --- a/src/rj_common/include/rj_common/live_frame.hpp +++ b/src/rj_common/include/rj_common/live_frame.hpp @@ -7,12 +7,11 @@ #include #include "rj_common/control/motion_setpoint.hpp" +#include "rj_common/debug_drawings.hpp" #include "rj_common/radio/robot_status.hpp" #include "rj_common/robot_intent.hpp" #include "rj_common/time.hpp" #include "rj_common/world_state.hpp" -#include "rj_common/debug_drawings.hpp" -#include "rj_common/radio/robot_status.hpp" namespace rj_common { @@ -24,7 +23,9 @@ struct LiveRobot { const rj_geometry::Point& pos() const { return position; } float angle() const { return static_cast(heading); } bool has_ball_sense_status() const { return true; } - BallSenseStatus ball_sense_status() const { return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; } + BallSenseStatus ball_sense_status() const { + return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; + } bool has_kicker_works() const { return false; } bool kicker_works() const { return kicker_ok; } const std::vector& motor_status() const { return motors; } @@ -43,7 +44,6 @@ struct LiveRobot { std::vector texts; }; - struct LiveBall { const rj_geometry::Point& pos() const { return position; } const rj_geometry::Point& vel() const { return velocity; } @@ -64,12 +64,16 @@ struct LiveFrame { bool has_ball() const { return ball_state.has_value(); } const LiveBall& ball() const { return *ball_state; } const std::vector& debug_paths() const { return debug_draw_frame.paths; } - const std::vector& debug_robot_paths() const { return debug_draw_frame.robot_paths; } + const std::vector& debug_robot_paths() const { + return debug_draw_frame.robot_paths; + } const std::vector& debug_circles() const { return debug_draw_frame.circles; } const std::vector& debug_arcs() const { return debug_draw_frame.arcs; } const std::vector& debug_polygons() const { return debug_draw_frame.polygons; } const std::vector& debug_texts() const { return debug_draw_frame.texts; } - int debug_layers_size() const { return static_cast(debug_draw_frame.debug_layers_.size()); } + int debug_layers_size() const { + return static_cast(debug_draw_frame.debug_layers_.size()); + } const std::string& debug_layers(int i) const { return debug_draw_frame.debug_layers_.at(i); } const std::vector& self() const { return self_; } @@ -92,18 +96,19 @@ struct LiveFrame { std::string yellow_name; DebugDrawFrame debug_draw_frame; - static void fill_robot(LiveRobot* out, int shell_id, RobotState const& state, RobotStatus const* status) { + static void fill_robot(LiveRobot* out, int shell_id, RobotState const& state, + RobotStatus const* status) { out->shell_id = shell_id; - + out->position = state.pose.position(); out->heading = state.pose.heading(); - + if (status != nullptr) { out->has_ball = status->has_ball; out->motors.resize(5); for (int i = 0; i < 5; i++) { - out->motors.at(i) = (status->motors_healthy[i] ? MotorStatus::Good - : MotorStatus::Fault); + out->motors.at(i) = + (status->motors_healthy[i] ? MotorStatus::Good : MotorStatus::Fault); } out->kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; out->battery = static_cast(status->battery_voltage); diff --git a/src/rj_ui/include/rj_ui/field_view.hpp b/src/rj_ui/include/rj_ui/field_view.hpp index 210c0c1c257..460920dce2d 100644 --- a/src/rj_ui/include/rj_ui/field_view.hpp +++ b/src/rj_ui/include/rj_ui/field_view.hpp @@ -15,9 +15,9 @@ #include #include +#include #include #include -#include #include #include #include diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index f47c4fb2d45..8147c0a61f3 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -13,8 +13,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/rj_ui/include/rj_ui/robot_status_widget.hpp b/src/rj_ui/include/rj_ui/robot_status_widget.hpp index 9db679b272b..6f3eca07011 100644 --- a/src/rj_ui/include/rj_ui/robot_status_widget.hpp +++ b/src/rj_ui/include/rj_ui/robot_status_widget.hpp @@ -7,9 +7,9 @@ #include #include -#include -#include #include +#include +#include #include #include "rj_ui/battery_profile.hpp" @@ -24,7 +24,8 @@ class RobotStatusWidget : public QWidget { public: RobotStatusWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); - void load(const RobotStatus& status, const std::optional& maybe_robot, bool blueTeam); + void load(const RobotStatus& status, + const std::optional& maybe_robot, bool blueTeam); [[nodiscard]] int shellID() const; void setShellID(int shellID); diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index 7d2a9bc14b6..1e8c4d5e64b 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -430,8 +430,8 @@ void FieldView::drawTeamSpace(QPainter& p) { QPointF center = qpointf(r.pos()); bool faulty = false; - if (r.has_ball_sense_status() && - (r.ball_sense_status() == rj_common::Dazzled || r.ball_sense_status() == rj_common::Failed)) { + if (r.has_ball_sense_status() && (r.ball_sense_status() == rj_common::Dazzled || + r.ball_sense_status() == rj_common::Failed)) { faulty = true; } if (r.has_kicker_works() && !r.kicker_works()) { diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 1a4e7d3f386..07cad7c0b94 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -64,7 +64,7 @@ void calcMinimumWidth(QWidget* widget, const QString& text) { MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* parent) : QMainWindow(parent), - _updateCount(0), + _updateCount(0), _lastUpdateTime(RJ::now()), _processor(processor), context_(processor->context()), @@ -75,7 +75,7 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par qRegisterMetaType>("QVector"); _ui.setupUi(this); _ui.fieldView->history(&_history); - + _ui.logTree->setVisible(false); _ui.logHistoryLocation->setVisible(false); _ui.logPlaybackRewind->setVisible(false); @@ -334,7 +334,8 @@ void MainWindow::updateViews() { // // Set the history vector by taking the last kHistorySize elements of the // // "long" history, or fewer if _longHistory is shorter. - _history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), context_->frames.end()); + _history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), + context_->frames.end()); // Update field view _ui.fieldView->update(); @@ -395,7 +396,7 @@ void MainWindow::updateViews() { for (size_t shell = 0; shell < kNumShells; shell++) { // Search for the corresponding references. auto maybe_rx = [&]() -> std::optional> { - for (auto & i : live_frame->radio_rx_) { + for (auto& i : live_frame->radio_rx_) { if (i.shell_id == shell) { return i; } diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index 813a7d3e9e7..dd708fcb7ea 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -30,7 +30,6 @@ Processor::Processor(bool /*sim*/, bool /*blue_team*/) : loop_mutex_() { world_state_queue_ = std::make_unique( "world_state_queue", vision_filter::topics::kWorldStateTopic); - } Processor::~Processor() { stop(); } diff --git a/src/rj_ui/src/robot_status_widget.cpp b/src/rj_ui/src/robot_status_widget.cpp index eb9b26e1263..7e913e38196 100644 --- a/src/rj_ui/src/robot_status_widget.cpp +++ b/src/rj_ui/src/robot_status_widget.cpp @@ -49,17 +49,23 @@ void RobotStatusWidget::setBoardID(const QString& boardID) { } QString RobotStatusWidget::robotModel() const { return _ui.robotModel->text(); } -void RobotStatusWidget::setRobotModel(const QString& robotModel) { _ui.robotModel->setText(robotModel); } -void RobotStatusWidget::setWheelFault(int wheelIndex, bool faulty) { _ui.robotWidget->setWheelFault(wheelIndex, faulty); } -void RobotStatusWidget::setBallSenseFault(bool faulty) { _ui.robotWidget->setBallSenseFault(faulty); } +void RobotStatusWidget::setRobotModel(const QString& robotModel) { + _ui.robotModel->setText(robotModel); +} +void RobotStatusWidget::setWheelFault(int wheelIndex, bool faulty) { + _ui.robotWidget->setWheelFault(wheelIndex, faulty); +} +void RobotStatusWidget::setBallSenseFault(bool faulty) { + _ui.robotWidget->setBallSenseFault(faulty); +} void RobotStatusWidget::setHasBall(bool hasBall) { _ui.robotWidget->setHasBall(hasBall); } bool RobotStatusWidget::hasRadio() const { return _hasRadio; } void RobotStatusWidget::setHasRadio(bool hasRadio) { if (hasRadio != _hasRadio) { _hasRadio = hasRadio; - _ui.radioIndicator->setPixmap(QPixmap(QString( - hasRadio ? ":icons/radio-connected.svg" : ":icons/radio-disconnected.svg"))); + _ui.radioIndicator->setPixmap(QPixmap( + QString(hasRadio ? ":icons/radio-connected.svg" : ":icons/radio-disconnected.svg"))); } } @@ -68,8 +74,8 @@ bool RobotStatusWidget::hasVision() const { return _hasVision; } void RobotStatusWidget::setHasVision(bool hasVision) { if (hasVision != _hasVision) { _hasVision = hasVision; - _ui.visionIndicator->setPixmap(QPixmap(QString( - hasVision ? ":icons/vision-available.svg" : ":icons/vision-unavailable.svg"))); + _ui.visionIndicator->setPixmap(QPixmap( + QString(hasVision ? ":icons/vision-available.svg" : ":icons/vision-unavailable.svg"))); } } @@ -97,11 +103,14 @@ void RobotStatusWidget::setShowstopper(bool showstopper) { } } -void RobotStatusWidget::load(const RobotStatus& status, const std::optional& maybe_robot, bool blueTeam) { +void RobotStatusWidget::load(const RobotStatus& status, + const std::optional& maybe_robot, + bool blueTeam) { setShellID(status.shell_id); setBlueTeam(blueTeam); - setRobotModel(status.version == RobotStatus::HardwareVersion::kSimulated ? "Simulation" : - status.version == RobotStatus::HardwareVersion::kFleet2018 ? "RJ2018" : "Unknown Bot"); + setRobotModel(status.version == RobotStatus::HardwareVersion::kSimulated ? "Simulation" + : status.version == RobotStatus::HardwareVersion::kFleet2018 ? "RJ2018" + : "Unknown Bot"); setHasRadio(status.timestamp != RJ::Time{}); setHasVision(maybe_robot.has_value()); @@ -110,8 +119,10 @@ void RobotStatusWidget::load(const RobotStatus& status, const std::optional(i), faulty); - else setBallSenseFault(faulty); + if (i < 4) + setWheelFault(static_cast(i), faulty); + else + setBallSenseFault(faulty); if (faulty) errors << QString("Motor Fault %1").arg(static_cast(i)); } @@ -120,10 +131,10 @@ void RobotStatusWidget::load(const RobotStatus& status, const std::optional(kRJ2015BatteryProfile.get_charge_level( - status.battery_voltage)); + const float battery = + status.version == RobotStatus::HardwareVersion::kSimulated + ? 1.0f + : static_cast(kRJ2015BatteryProfile.get_charge_level(status.battery_voltage)); setBatteryLevel(battery); setErrorText(errors.join(", ")); setShowstopper(!maybe_robot.has_value() || motorFault || kickerFault || battery < 0.25f || diff --git a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp index 8203cd73fa6..e4fa2950856 100644 --- a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp +++ b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp @@ -38,7 +38,8 @@ void DebugDrawInterface::run() { } for (const auto& path : debug_draw->paths) { DebugRobotPath& debug_path = context_->debug_drawer.add_debug_path(); - debug_path.set_layer(context_->debug_drawer.find_debug_layer(QString::fromStdString(layer))); + debug_path.set_layer( + context_->debug_drawer.find_debug_layer(QString::fromStdString(layer))); for (const auto& point : path.points) { DebugRobotPath::DebugRobotPathPoint& new_point = debug_path.add_points(); new_point.mutable_pos() = rj_geometry::Point(point.x, point.y); diff --git a/src/rj_utils/include/rj_utils/log_utils.hpp b/src/rj_utils/include/rj_utils/log_utils.hpp index 2640b4e06d6..ba6b1c88d21 100644 --- a/src/rj_utils/include/rj_utils/log_utils.hpp +++ b/src/rj_utils/include/rj_utils/log_utils.hpp @@ -13,9 +13,7 @@ static inline QColor qcolor(uint32_t value) { return QColor(r, g, b, a); } -static inline QPointF qpointf(const rj_geometry::Point& pt) { - return pt.to_q_point_f(); -} +static inline QPointF qpointf(const rj_geometry::Point& pt) { return pt.to_q_point_f(); } static inline uint32_t color(const QColor& color) { return (color.red() << 16) | (color.green() << 8) | (color.blue()) | (color.alpha() << 24); From 7592035c937604a381be0dcf7367896fb508fb8c Mon Sep 17 00:00:00 2001 From: Sanat Dhanyamraju Date: Fri, 25 Sep 2026 20:58:09 -0400 Subject: [PATCH 07/21] comments --- src/rj_common/include/rj_common/context.hpp | 51 +++-- .../include/rj_common/debug_drawer.hpp | 2 +- .../include/rj_common/debug_drawings.hpp | 87 +++----- .../include/rj_common/live_frame.hpp | 119 ----------- src/rj_common/include/rj_common/ui_frame.hpp | 60 ++++++ src/rj_common/src/debug_drawer.cpp | 44 ++--- src/rj_common/src/planning/trajectory.cpp | 8 +- src/rj_ui/include/rj_ui/field_view.hpp | 14 +- src/rj_ui/include/rj_ui/main_window.hpp | 6 +- src/rj_ui/include/rj_ui/processor.hpp | 2 +- .../include/rj_ui/robot_status_widget.hpp | 4 +- src/rj_ui/src/field_view.cpp | 186 +++++++++--------- src/rj_ui/src/main_window.cpp | 42 ++-- src/rj_ui/src/processor.cpp | 2 +- src/rj_ui/src/robot_status_widget.cpp | 2 +- .../src/ros2_temp/debug_draw_interface.cpp | 8 +- src/rj_ui/src/sim_field_view.cpp | 34 ++-- 17 files changed, 293 insertions(+), 378 deletions(-) delete mode 100644 src/rj_common/include/rj_common/live_frame.hpp create mode 100644 src/rj_common/include/rj_common/ui_frame.hpp diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index abbd71eb829..57aee94923f 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -10,12 +10,12 @@ #include "rj_common/debug_drawer.hpp" #include "rj_common/game_settings.hpp" #include "rj_common/game_state.hpp" -#include "rj_common/live_frame.hpp" #include "rj_common/planning/robot_constraints.hpp" #include "rj_common/planning/trajectory.hpp" #include "rj_common/radio/robot_status.hpp" #include "rj_common/robot_intent.hpp" #include "rj_common/team_info.hpp" +#include "rj_common/ui_frame.hpp" #include "rj_common/world_state.hpp" struct Context { @@ -64,58 +64,73 @@ struct Context { std::string behavior_tree; - std::vector> frames; + std::vector> frames; RJ::Time start_time; }; -static std::shared_ptr create_log_frame(const Context& context) { - // Add everything to the log frame. - auto frame = std::make_shared(); +inline rj_common::UIRobot create_ui_robot(int shell_id, const RobotState& state, + const std::optional& status) { + rj_common::UIRobot out; + out.shell_id = shell_id; + + out.position = state.pose.position(); + out.heading = state.pose.heading(); + + if (status != std::nullopt) { + out.has_ball = status->has_ball; + out.motors.resize(5); + for (int i = 0; i < 5; i++) { + out.motors.at(i) = + (status->motors_healthy[i] ? + rj_common::MotorStatus::kGood : rj_common::MotorStatus::kFault); + } + out.kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; + out.battery = static_cast(status->battery_voltage); + } + return out; +} - // Debug drawing +inline std::shared_ptr create_ui_frame(const Context& context) { + auto frame = std::make_shared(); + frame->debug_draw_frame = context.debug_drawer.published_frame(); frame->blue = context.blue_team; - // Our robots for (size_t shell = 0; shell < kNumShells; shell++) { const auto& state = context.world_state.our_robots.at(shell); const auto& status = context.robot_status.at(shell); if (RJ::now() - status.timestamp < RJ::Seconds(0.5)) { - frame->radio_rx_.push_back(status); + frame->radio_rx.push_back(status); } if (!state.visible) { continue; } - rj_common::LiveFrame::fill_robot(&frame->self_.emplace_back(), shell, state, &status); + frame->self.push_back(create_ui_robot(shell, state, status)); } - // Opponent robots for (size_t shell = 0; shell < kNumShells; shell++) { const auto& state = context.world_state.their_robots.at(shell); if (!state.visible) { continue; } - rj_common::LiveFrame::fill_robot(&frame->opp_.emplace_back(), shell, state, nullptr); + frame->opp.push_back(create_ui_robot(shell, state, std::nullopt)); } - // Ball if (context.world_state.ball.visible) { frame->ball_state = {context.world_state.ball.position, context.world_state.ball.velocity}; } - // Field - frame->manual = context.game_settings.joystick_config.manual_id; - frame->defend_plus = context.game_settings.defend_plus_x; - frame->use_our = context.game_settings.use_our_half; - frame->use_opponent = context.game_settings.use_their_half; + frame->manual_id = context.game_settings.joystick_config.manual_id; + frame->defend_plus_x = context.game_settings.defend_plus_x; + frame->use_our_half = context.game_settings.use_our_half; + frame->use_their_half = context.game_settings.use_their_half; - // Team names if (context.blue_team) { frame->yellow_name = context.their_info.name; frame->blue_name = context.our_info.name; diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 0d7728efc99..5c3bd344e16 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -86,7 +86,7 @@ class DebugDrawer { published_ = std::move(current_); current_.clear(); for (const QString& string : debug_layers_) { - current_.debug_layers_.push_back(string.toStdString()); + current_.debug_layers.push_back(string.toStdString()); } } diff --git a/src/rj_common/include/rj_common/debug_drawings.hpp b/src/rj_common/include/rj_common/debug_drawings.hpp index d6cc23bc1a0..f87c23f63d5 100644 --- a/src/rj_common/include/rj_common/debug_drawings.hpp +++ b/src/rj_common/include/rj_common/debug_drawings.hpp @@ -6,87 +6,54 @@ #include struct DebugPath { - int layer() const { return layer_; } - uint32_t color() const { return color_; } - int points_size() const { return static_cast(points_.size()); } - const rj_geometry::Point& points(int i) const { return points_.at(i); } - - int layer_ = -1; - uint32_t color_ = 0; - std::vector points_; + int layer = -1; + uint32_t color = 0; + std::vector points; }; struct DebugRobotPath { struct DebugRobotPathPoint { - const rj_geometry::Point& pos() const { return pos_; } - const rj_geometry::Point& vel() const { return vel_; } - rj_geometry::Point& mutable_pos() { return pos_; } - rj_geometry::Point& mutable_vel() { return vel_; } - - rj_geometry::Point pos_; - rj_geometry::Point vel_; + rj_geometry::Point pos; + rj_geometry::Point vel; }; - - int layer() const { return layer_; } - void set_layer(int layer) { layer_ = layer; } - int points_size() const { return static_cast(points_.size()); } - const DebugRobotPathPoint& points(int i) const { return points_.at(i); } - DebugRobotPathPoint& add_points() { return points_.emplace_back(); } - - int layer_ = -1; - std::vector points_; + + int layer = -1; + std::vector points; }; struct DebugCircle { - int layer() const { return layer_; } - uint32_t color() const { return color_; } - const rj_geometry::Point& center() const { return center_; } - float radius() const { return radius_; } - - int layer_ = -1; - uint32_t color_ = 0; - rj_geometry::Point center_; - float radius_ = 0; + int layer = -1; + uint32_t color = 0; + rj_geometry::Point center; + float radius = 0; }; struct DebugArc { - int layer() const { return layer_; } - uint32_t color() const { return color_; } - const rj_geometry::Point& center() const { return center_; } - float radius() const { return radius_; } - float start() const { return start_; } - float end() const { return end_; } - - int layer_ = -1; - uint32_t color_ = 0; - rj_geometry::Point center_; - float radius_ = 0; - float start_ = 0; - float end_ = 0; + int layer = -1; + uint32_t color = 0; + rj_geometry::Point center; + float radius = 0; + float start = 0; + float end = 0; }; struct DebugText { - int layer() const { return layer_; } - uint32_t color() const { return color_; } - const rj_geometry::Point& pos() const { return pos_; } - const std::string& text() const { return text_; } - bool center() const { return center_; } - - int layer_ = -1; - uint32_t color_ = 0; - rj_geometry::Point pos_; - std::string text_; - bool center_ = true; + int layer = -1; + uint32_t color = 0; + rj_geometry::Point pos; + std::string text; + bool center = true; }; -struct DebugDrawFrame { +class DebugDrawFrame { +public: std::vector paths; std::vector polygons; std::vector circles; std::vector arcs; std::vector texts; std::vector robot_paths; - std::vector debug_layers_; + std::vector debug_layers; void clear() { paths.clear(); @@ -95,6 +62,6 @@ struct DebugDrawFrame { arcs.clear(); texts.clear(); robot_paths.clear(); - debug_layers_.clear(); + debug_layers.clear(); } }; diff --git a/src/rj_common/include/rj_common/live_frame.hpp b/src/rj_common/include/rj_common/live_frame.hpp deleted file mode 100644 index 36aa5e67fae..00000000000 --- a/src/rj_common/include/rj_common/live_frame.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "rj_common/control/motion_setpoint.hpp" -#include "rj_common/debug_drawings.hpp" -#include "rj_common/radio/robot_status.hpp" -#include "rj_common/robot_intent.hpp" -#include "rj_common/time.hpp" -#include "rj_common/world_state.hpp" - -namespace rj_common { - -enum BallSenseStatus { NoBall, HasBall, Dazzled, Failed }; -enum MotorStatus { Good, Fault }; - -struct LiveRobot { - int shell() const { return shell_id; } - const rj_geometry::Point& pos() const { return position; } - float angle() const { return static_cast(heading); } - bool has_ball_sense_status() const { return true; } - BallSenseStatus ball_sense_status() const { - return has_ball ? BallSenseStatus::HasBall : BallSenseStatus::NoBall; - } - bool has_kicker_works() const { return false; } - bool kicker_works() const { return kicker_ok; } - const std::vector& motor_status() const { return motors; } - MotorStatus motor_status(int index) const { return motors.at(index); } - bool has_battery_voltage() const { return true; } - float battery_voltage() const { return battery; } - const std::vector& text() const { return texts; } - - int shell_id = -1; - rj_geometry::Point position; - double heading = 0; - bool has_ball = false; - bool kicker_ok = true; - float battery = 0; - std::vector motors; - std::vector texts; -}; - -struct LiveBall { - const rj_geometry::Point& pos() const { return position; } - const rj_geometry::Point& vel() const { return velocity; } - rj_geometry::Point position; - rj_geometry::Point velocity; -}; - -struct LiveFrame { - using Robot = LiveRobot; - - bool defend_plus_x() const { return defend_plus; } - bool use_our_half() const { return use_our; } - bool use_opponent_half() const { return use_opponent; } - bool blue_team() const { return blue; } - int manual_id() const { return manual; } - const std::string& team_name_blue() const { return blue_name; } - const std::string& team_name_yellow() const { return yellow_name; } - bool has_ball() const { return ball_state.has_value(); } - const LiveBall& ball() const { return *ball_state; } - const std::vector& debug_paths() const { return debug_draw_frame.paths; } - const std::vector& debug_robot_paths() const { - return debug_draw_frame.robot_paths; - } - const std::vector& debug_circles() const { return debug_draw_frame.circles; } - const std::vector& debug_arcs() const { return debug_draw_frame.arcs; } - const std::vector& debug_polygons() const { return debug_draw_frame.polygons; } - const std::vector& debug_texts() const { return debug_draw_frame.texts; } - int debug_layers_size() const { - return static_cast(debug_draw_frame.debug_layers_.size()); - } - const std::string& debug_layers(int i) const { return debug_draw_frame.debug_layers_.at(i); } - - const std::vector& self() const { return self_; } - const std::vector& opp() const { return opp_; } - const LiveRobot& self(int index) const { return self_.at(index); } - const LiveRobot& opp(int index) const { return opp_.at(index); } - int self_size() const { return static_cast(self_.size()); } - int opp_size() const { return static_cast(opp_.size()); } - - std::vector self_; - std::vector opp_; - std::vector radio_rx_; - std::optional ball_state; - bool blue = true; - bool defend_plus = false; - bool use_our = true; - bool use_opponent = true; - int manual = -1; - std::string blue_name; - std::string yellow_name; - DebugDrawFrame debug_draw_frame; - - static void fill_robot(LiveRobot* out, int shell_id, RobotState const& state, - RobotStatus const* status) { - out->shell_id = shell_id; - - out->position = state.pose.position(); - out->heading = state.pose.heading(); - - if (status != nullptr) { - out->has_ball = status->has_ball; - out->motors.resize(5); - for (int i = 0; i < 5; i++) { - out->motors.at(i) = - (status->motors_healthy[i] ? MotorStatus::Good : MotorStatus::Fault); - } - out->kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; - out->battery = static_cast(status->battery_voltage); - } - } -}; - -} // namespace rj_common diff --git a/src/rj_common/include/rj_common/ui_frame.hpp b/src/rj_common/include/rj_common/ui_frame.hpp new file mode 100644 index 00000000000..0c9e76d0eca --- /dev/null +++ b/src/rj_common/include/rj_common/ui_frame.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "rj_common/control/motion_setpoint.hpp" +#include "rj_common/debug_drawings.hpp" +#include "rj_common/radio/robot_status.hpp" +#include "rj_common/robot_intent.hpp" +#include "rj_common/time.hpp" +#include "rj_common/world_state.hpp" + +namespace rj_common { + +enum BallSenseStatus { + kNoBall = 0, + kHasBall, + kDazzled, + kFailed +}; +enum MotorStatus { + kGood = 0, + kFault +}; + +struct UIRobot { + int shell_id = -1; + rj_geometry::Point position; + double heading = 0; + bool has_ball = false; + bool kicker_ok = true; + float battery = 0; + std::vector motors; + std::vector texts; +}; + +struct UIBall { + rj_geometry::Point position; + rj_geometry::Point velocity; +}; + +struct UIFrame { + std::vector self; + std::vector opp; + std::vector radio_rx; + std::optional ball_state; + bool blue = true; + bool defend_plus_x = false; + bool use_our_half = true; + bool use_their_half = true; + int manual_id = -1; + std::string blue_name; + std::string yellow_name; + DebugDrawFrame debug_draw_frame; +}; + +} // namespace rj_common diff --git a/src/rj_common/src/debug_drawer.cpp b/src/rj_common/src/debug_drawer.cpp index 96c6bed72dd..1c2f6a9a6cb 100644 --- a/src/rj_common/src/debug_drawer.cpp +++ b/src/rj_common/src/debug_drawer.cpp @@ -23,11 +23,11 @@ int DebugDrawer::find_debug_layer(QString layer) { void DebugDrawer::draw_polygon(const rj_geometry::Point* pts, int n, const QColor& qc, const QString& layer) { DebugPath dbg; - dbg.layer_ = find_debug_layer(layer); - dbg.color_ = color(qc); - dbg.points_.reserve(n); + dbg.layer = find_debug_layer(layer); + dbg.color = color(qc); + dbg.points.reserve(n); for (int i = 0; i < n; ++i) { - dbg.points_.push_back(pts[i]); + dbg.points.push_back(pts[i]); } current_.polygons.push_back(std::move(dbg)); } @@ -45,21 +45,21 @@ void DebugDrawer::draw_polygon(const rj_geometry::Polygon& polygon, const QColor void DebugDrawer::draw_circle(rj_geometry::Point center, float radius, const QColor& qc, const QString& layer) { DebugCircle dbg; - dbg.layer_ = find_debug_layer(layer); - dbg.center_ = center; - dbg.radius_ = radius; - dbg.color_ = color(qc); + dbg.layer = find_debug_layer(layer); + dbg.center = center; + dbg.radius = radius; + dbg.color = color(qc); current_.circles.push_back(dbg); } void DebugDrawer::draw_arc(const rj_geometry::Arc& arc, const QColor& qc, const QString& layer) { DebugArc dbg; - dbg.layer_ = find_debug_layer(layer); - dbg.center_ = arc.center(); - dbg.radius_ = static_cast(arc.radius()); - dbg.start_ = static_cast(arc.start()); - dbg.end_ = static_cast(arc.end()); - dbg.color_ = color(qc); + dbg.layer = find_debug_layer(layer); + dbg.center = arc.center(); + dbg.radius = static_cast(arc.radius()); + dbg.start = static_cast(arc.start()); + dbg.end = static_cast(arc.end()); + dbg.color = color(qc); current_.arcs.push_back(dbg); } @@ -100,10 +100,10 @@ void DebugDrawer::draw_shape_set(const rj_geometry::ShapeSet& shapes, const QCol void DebugDrawer::draw_line(const rj_geometry::Segment& line, const QColor& qc, const QString& layer) { DebugPath dbg; - dbg.layer_ = find_debug_layer(layer); - dbg.points_.push_back(line.pt[0]); - dbg.points_.push_back(line.pt[1]); - dbg.color_ = color(qc); + dbg.layer = find_debug_layer(layer); + dbg.points.push_back(line.pt[0]); + dbg.points.push_back(line.pt[1]); + dbg.color = color(qc); current_.paths.push_back(std::move(dbg)); } @@ -115,10 +115,10 @@ void DebugDrawer::draw_line(rj_geometry::Point p0, rj_geometry::Point p1, const void DebugDrawer::draw_text(const QString& text, rj_geometry::Point pos, const QColor& qc, const QString& layer) { DebugText dbg; - dbg.layer_ = find_debug_layer(layer); - dbg.text_ = text.toStdString(); - dbg.pos_ = pos; - dbg.color_ = color(qc); + dbg.layer = find_debug_layer(layer); + dbg.text = text.toStdString(); + dbg.pos = pos; + dbg.color = color(qc); current_.texts.push_back(std::move(dbg)); } diff --git a/src/rj_common/src/planning/trajectory.cpp b/src/rj_common/src/planning/trajectory.cpp index 1621baf1783..3da3c1ab110 100644 --- a/src/rj_common/src/planning/trajectory.cpp +++ b/src/rj_common/src/planning/trajectory.cpp @@ -185,12 +185,12 @@ void Trajectory::draw(DebugDrawer* drawer, std::optional alt_text_position) const { if (instants_.size() > 1) { DebugRobotPath& dbg_path = drawer->add_debug_path(); - dbg_path.set_layer(drawer->find_debug_layer("Motion")); + dbg_path.layer = drawer->find_debug_layer("Motion"); for (const RobotInstant& instant : instants_) { - DebugRobotPath::DebugRobotPathPoint& pt = dbg_path.add_points(); - pt.mutable_pos() = instant.pose.position(); - pt.mutable_vel() = instant.velocity.linear(); + DebugRobotPath::DebugRobotPathPoint& pt = dbg_path.points.emplace_back(); + pt.pos = instant.pose.position(); + pt.vel = instant.velocity.linear(); } } diff --git a/src/rj_ui/include/rj_ui/field_view.hpp b/src/rj_ui/include/rj_ui/field_view.hpp index 460920dce2d..f71d64774a1 100644 --- a/src/rj_ui/include/rj_ui/field_view.hpp +++ b/src/rj_ui/include/rj_ui/field_view.hpp @@ -15,8 +15,8 @@ #include #include -#include #include +#include #include #include #include @@ -46,8 +46,8 @@ class FieldView : public QWidget { } } - void history(const std::vector >* value) { - _history = value; + void setHistory(std::vector>&& value) { + _history = std::move(value); } void rotate(int value); @@ -76,7 +76,7 @@ class FieldView : public QWidget { void drawText(QPainter& p, QPointF pos, const QString& text, bool center = true) const; - static void drawField(QPainter& p, const rj_common::LiveFrame* frame); + static void drawField(QPainter& p, const std::shared_ptr& frame); void drawRobot(QPainter& p, bool blueRobot, int ID, QPointF pos, float theta, bool hasBall = false, bool faulty = false); void drawCoords(QPainter& p); @@ -95,9 +95,9 @@ class FieldView : public QWidget { protected: // Returns a pointer to the most recent frame, or null if none is available. - std::shared_ptr currentFrame(); + std::shared_ptr currentFrame(); - // Coordirj_common::LiveFramenate transformations + // Coordinate transformations rj_geometry::TransformMatrix _screenToWorld; rj_geometry::TransformMatrix _worldToTeam; rj_geometry::TransformMatrix _teamToWorld; @@ -111,7 +111,7 @@ class FieldView : public QWidget { // How many degrees to rotate text so it shows up the right way on screen int _textRotation{}; - const std::vector >* _history{}; + std::vector> _history; QVector _layerVisible; }; diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 6a58d4bf51f..f03ec8d5a50 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -190,7 +190,7 @@ private Q_SLOTS: private: void updateStatus(); void updateFromRefPacket(bool haveExternalReferee); - void updateDebugLayers(const rj_common::LiveFrame& frame); + void updateDebugLayers(const rj_common::UIFrame& frame); static std::string formatLabelBold(Side side, const std::string& label); enum class StatusType { Status_OK, Status_Warning, Status_Fail }; @@ -248,9 +248,7 @@ private Q_SLOTS: std::mutex* context__mutex; Context* context_; - - std::vector> _history{}; - + // ROS Compatibility stuff void send_quick_command(const PlayState& state); diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index 8147c0a61f3..27a9a5599e1 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -14,8 +14,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/src/rj_ui/include/rj_ui/robot_status_widget.hpp b/src/rj_ui/include/rj_ui/robot_status_widget.hpp index 6f3eca07011..864be83b4aa 100644 --- a/src/rj_ui/include/rj_ui/robot_status_widget.hpp +++ b/src/rj_ui/include/rj_ui/robot_status_widget.hpp @@ -7,9 +7,9 @@ #include #include -#include #include #include +#include #include #include "rj_ui/battery_profile.hpp" @@ -25,7 +25,7 @@ class RobotStatusWidget : public QWidget { RobotStatusWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); void load(const RobotStatus& status, - const std::optional& maybe_robot, bool blueTeam); + const std::optional& maybe_robot, bool blueTeam); [[nodiscard]] int shellID() const; void setShellID(int shellID); diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index 1e8c4d5e64b..2457f4e8cb4 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -46,7 +47,6 @@ FieldView::FieldView(QWidget* parent) : QWidget(parent) { showDotPatterns = false; showTeamNames = false; _rotate = 1; - _history = nullptr; // Green background QPalette p = palette(); @@ -80,11 +80,11 @@ void FieldView::mouseMoveEvent(QMouseEvent* me) { _posLabel->setText(s); } -std::shared_ptr FieldView::currentFrame() { - if (_history != nullptr && !_history->empty()) { - return _history->back(); +std::shared_ptr FieldView::currentFrame() { + if (!_history.empty()) { + return _history.back(); } - return std::shared_ptr(); + return std::shared_ptr{}; } void FieldView::rotate(int value) { @@ -126,7 +126,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { } // Get the latest LogFrame - const std::shared_ptr frame = currentFrame(); + const std::shared_ptr frame = currentFrame(); if (!frame) { // No data available yet @@ -148,14 +148,14 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { _worldToTeam = rj_geometry::TransformMatrix(); _worldToTeam *= rj_geometry::TransformMatrix::translate( 0, FieldDimensions::current_dimensions.length() / 2.0f); - if (frame->defend_plus_x()) { + if (frame->defend_plus_x) { _worldToTeam *= rj_geometry::TransformMatrix::rotate(-M_PI / 2.0); } else { _worldToTeam *= rj_geometry::TransformMatrix::rotate(M_PI / 2.0); } _teamToWorld = rj_geometry::TransformMatrix(); - if (frame->defend_plus_x()) { + if (frame->defend_plus_x) { _teamToWorld *= rj_geometry::TransformMatrix::rotate(M_PI / 2.0); } else { _teamToWorld *= rj_geometry::TransformMatrix::rotate(-M_PI / 2.0); @@ -168,7 +168,7 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { // Everything after this point is drawn in team space. // Transform that into world space depending on defending goal. - if (frame->defend_plus_x()) { + if (frame->defend_plus_x) { p.rotate(90); } else { p.rotate(-90); @@ -176,14 +176,14 @@ void FieldView::paintEvent(QPaintEvent* /*e*/) { p.translate(0, -FieldDimensions::current_dimensions.length() / 2.0f); // Text has to be rotated so it is always upright on screen - _textRotation = -_rotate * 90 + (frame->defend_plus_x() ? -90 : 90); + _textRotation = -_rotate * 90 + (frame->defend_plus_x ? -90 : 90); drawTeamSpace(p); } void FieldView::drawWorldSpace(QPainter& p) { // Get the latest LogFrame - const rj_common::LiveFrame* frame = _history->back().get(); + const std::shared_ptr frame = _history.back(); // Draw the field drawField(p, frame); @@ -192,7 +192,7 @@ void FieldView::drawWorldSpace(QPainter& p) { void FieldView::drawTeamSpace(QPainter& p) { // Get the latest LogFrame - const rj_common::LiveFrame* frame = _history->back().get(); + const std::shared_ptr frame = _history.back(); if (showTeamNames) { // Draw Team Names @@ -201,22 +201,22 @@ void FieldView::drawTeamSpace(QPainter& p) { fontstyle.setPointSize(20); p.setFont(fontstyle); p.setPen(bluePen); - drawText(p, QPointF(0, 4.75), QString(frame->team_name_blue().c_str()), + drawText(p, QPointF(0, 4.75), QString(frame->blue_name.c_str()), true); // Blue p.setPen(yellowPen); - drawText(p, QPointF(0, 1.75), QString(frame->team_name_yellow().c_str()), + drawText(p, QPointF(0, 1.75), QString(frame->yellow_name.c_str()), true); // Yellow p.setFont(savedFont); } // Block off half the field - if (!frame->use_our_half()) { + if (!frame->use_our_half) { const float FX = FieldDimensions::current_dimensions.floor_width() / 2; const float FY1 = -FieldDimensions::current_dimensions.border(); const float FY2 = FieldDimensions::current_dimensions.length() / 2; p.fillRect(QRectF(QPointF(-FX, FY1), QPointF(FX, FY2)), QColor(0, 0, 0, 128)); } - if (!frame->use_opponent_half()) { + if (!frame->use_their_half) { const float FX = FieldDimensions::current_dimensions.floor_width() / 2; const float FY1 = FieldDimensions::current_dimensions.length() / 2; const float FY2 = FieldDimensions::current_dimensions.length() + @@ -233,11 +233,11 @@ void FieldView::drawTeamSpace(QPainter& p) { QPainterPath ballTrail; bool move = false; int ballTrailLength = 60; - for (unsigned int i = _history->size() - std::min(_history->size(), ballTrailLength); - i < _history->size(); ++i) { - const rj_common::LiveFrame* oldFrame = _history->at(i).get(); - if (oldFrame != nullptr && oldFrame->has_ball()) { - QPointF pos = qpointf(oldFrame->ball().pos()); + for (unsigned int i = _history.size() - std::min(_history.size(), ballTrailLength); + i < _history.size(); ++i) { + const std::shared_ptr oldFrame = _history.at(i); + if (oldFrame != nullptr && oldFrame->ball_state.has_value()) { + QPointF pos = qpointf(oldFrame->ball_state->position); if (!move) { ballTrail.moveTo(pos); @@ -253,26 +253,26 @@ void FieldView::drawTeamSpace(QPainter& p) { p.drawPath(ballTrail); // Debug lines - for (const DebugPath& path : frame->debug_paths()) { - if (path.layer() < 0 || layerVisible(path.layer())) { - tempPen.setColor(qcolor(path.color())); + for (const DebugPath& path : frame->debug_draw_frame.paths) { + if (path.layer < 0 || layerVisible(path.layer)) { + tempPen.setColor(qcolor(path.color)); p.setPen(tempPen); std::vector pts; - for (int i = 0; i < path.points_size(); ++i) { - pts.push_back(qpointf(path.points(i))); + for (int i = 0; i < path.points.size(); ++i) { + pts.push_back(qpointf(path.points.at(i))); } p.drawPolyline(pts.data(), pts.size()); } } - for (const DebugRobotPath& path : frame->debug_robot_paths()) { - if (path.layer() < 0 || layerVisible(path.layer())) { - for (int i = 0; i < path.points_size() - 1; ++i) { - const DebugRobotPath::DebugRobotPathPoint& from = path.points(i); - const DebugRobotPath::DebugRobotPathPoint& to = path.points(i + 1); + for (const DebugRobotPath& path : frame->debug_draw_frame.robot_paths) { + if (!path.points.empty() && (path.layer < 0 || layerVisible(path.layer))) { + for (int i = 0; i < path.points.size() - 1; ++i) { + const DebugRobotPath::DebugRobotPathPoint& from = path.points.at(i); + const DebugRobotPath::DebugRobotPathPoint& to = path.points.at(i + 1); - rj_geometry::Point avgVel = (rj_geometry::Point(path.points(i).vel()) + - rj_geometry::Point(path.points(i + 1).vel())) / + rj_geometry::Point avgVel = (rj_geometry::Point(path.points.at(i).vel) + + rj_geometry::Point(path.points.at(i + 1).vel)) / 2; auto pcntMaxSpd = static_cast(avgVel.mag() / planning::MotionConstraints{}.max_speed); @@ -283,38 +283,38 @@ void FieldView::drawTeamSpace(QPainter& p) { pen.setWidthF(0.03); p.setPen(pen); - const rj_geometry::Point fromPos = rj_geometry::Point(from.pos()); - const rj_geometry::Point toPos = rj_geometry::Point(to.pos()); + const rj_geometry::Point fromPos = rj_geometry::Point(from.pos); + const rj_geometry::Point toPos = rj_geometry::Point(to.pos); p.drawLine(fromPos.to_q_point_f(), toPos.to_q_point_f()); } } } // Debug circles - for (const DebugCircle& c : frame->debug_circles()) { - if (c.layer() < 0 || layerVisible(c.layer())) { - QColor fill_color(c.color()); + for (const DebugCircle& c : frame->debug_draw_frame.circles) { + if (c.layer < 0 || layerVisible(c.layer)) { + QColor fill_color(c.color); fill_color.setAlpha(0); p.setBrush(fill_color); - QColor color(c.color()); + QColor color(c.color); color.setAlpha(255); tempPen.setColor(color); p.setPen(tempPen); - p.drawEllipse(qpointf(c.center()), c.radius(), c.radius()); + p.drawEllipse(qpointf(c.center), c.radius, c.radius); } } // Debug arcs - for (const DebugArc& a : frame->debug_arcs()) { - if (a.layer() < 0 || layerVisible(a.layer())) { - tempPen.setColor(a.color()); + for (const DebugArc& a : frame->debug_draw_frame.arcs) { + if (a.layer < 0 || layerVisible(a.layer)) { + tempPen.setColor(a.color); p.setPen(tempPen); - const auto& c = a.center(); - auto t1 = a.start(); - auto t2 = a.end(); - auto R = a.radius(); + const auto& c = a.center; + auto t1 = a.start; + auto t2 = a.end; + auto R = a.radius; QRectF rect; rect.setX(-R + c.x()); @@ -331,14 +331,14 @@ void FieldView::drawTeamSpace(QPainter& p) { // Debug polygons p.setPen(Qt::NoPen); - for (const DebugPath& polygon : frame->debug_polygons()) { - if (polygon.layer() < 0 || layerVisible(polygon.layer())) { - if (polygon.points_size() < 3) { - fprintf(stderr, "Ignoring DebugPolygon with %d points\n", polygon.points_size()); + for (const DebugPath& polygon : frame->debug_draw_frame.polygons) { + if (polygon.layer < 0 || layerVisible(polygon.layer)) { + if (polygon.points.size() < 3) { + fprintf(stderr, "Ignoring DebugPolygon with %zu points\n", polygon.points.size()); continue; } - QColor color = qcolor(polygon.color()); + QColor color = qcolor(polygon.color); p.setBrush(color); color.setAlpha(255); @@ -346,8 +346,8 @@ void FieldView::drawTeamSpace(QPainter& p) { p.setPen(tempPen); std::vector pts; - for (int i = 0; i < polygon.points_size(); ++i) { - pts.push_back(qpointf(polygon.points(i))); + for (int i = 0; i < polygon.points.size(); ++i) { + pts.push_back(qpointf(polygon.points.at(i))); } p.drawConvexPolygon(pts.data(), pts.size()); } @@ -355,11 +355,11 @@ void FieldView::drawTeamSpace(QPainter& p) { p.setBrush(Qt::NoBrush); // Debug text - for (const DebugText& text : frame->debug_texts()) { - if (text.layer() < 0 || layerVisible(text.layer())) { - tempPen.setColor(text.color()); + for (const DebugText& text : frame->debug_draw_frame.texts) { + if (text.layer < 0 || layerVisible(text.layer)) { + tempPen.setColor(text.color); p.setPen(tempPen); - drawText(p, qpointf(text.pos()), QString::fromStdString(text.text()), text.center()); + drawText(p, qpointf(text.pos), QString::fromStdString(text.text), text.center); } } @@ -371,14 +371,14 @@ void FieldView::drawTeamSpace(QPainter& p) { /// populate @cometTrails with the past locations of each robot int pastLocationCount = 40; // number of past locations to show - int start = std::max(0, static_cast(_history->size()) - pastLocationCount); - for (size_t i = start; i < _history->size(); i++) { - const rj_common::LiveFrame* oldFrame = _history->at(i).get(); + int start = std::max(0, static_cast(_history.size()) - pastLocationCount); + for (size_t i = start; i < _history.size(); i++) { + const std::shared_ptr oldFrame = _history.at(i); if (oldFrame != nullptr) { - for (const rj_common::LiveFrame::Robot& r : oldFrame->self()) { - pair key(1, r.shell()); + for (const rj_common::UIRobot& r : oldFrame->self) { + pair key(1, r.shell_id); if (cometTrails.find(key) != cometTrails.end() || i == start) { - QPointF pt = qpointf(r.pos()); + QPointF pt = qpointf(r.position); if (i == start) { cometTrails[key].moveTo(pt); } else { @@ -387,10 +387,10 @@ void FieldView::drawTeamSpace(QPainter& p) { } } - for (const rj_common::LiveFrame::Robot& r : oldFrame->opp()) { - pair key(2, r.shell()); + for (const rj_common::UIRobot& r : oldFrame->opp) { + pair key(2, r.shell_id); if (cometTrails.find(key) != cometTrails.end() || i == start) { - QPointF pt = qpointf(r.pos()); + QPointF pt = qpointf(r.position); if (i == start) { cometTrails[key].moveTo(pt); } else { @@ -406,7 +406,7 @@ void FieldView::drawTeamSpace(QPainter& p) { for (auto& kv : cometTrails) { // note: kv.first.first is 1 for our team and 2 for their team bool ourTeam = kv.first.first == 1; - bool blue = frame->blue_team(); + bool blue = frame->blue; const QColor color = (ourTeam ^ blue) != 0 ? Qt::yellow : Qt::blue; QPen pen(color, cometTrailPenSize); pen.setCapStyle(Qt::RoundCap); @@ -419,38 +419,32 @@ void FieldView::drawTeamSpace(QPainter& p) { QPointF rtY = qpointf(rj_geometry::Point(-1, 0).rotated(-_rotate * 90)); // Opponent robots - for (const rj_common::LiveFrame::Robot& r : frame->opp()) { - drawRobot(p, !frame->blue_team(), r.shell(), qpointf(r.pos()), r.angle(), - r.ball_sense_status() == rj_common::HasBall); + for (const rj_common::UIRobot& r : frame->opp) { + drawRobot(p, !frame->blue, r.shell_id, qpointf(r.position), r.heading, + r.has_ball); } // Our robots - int manualID = frame->manual_id(); - for (const rj_common::LiveFrame::Robot& r : frame->self()) { - QPointF center = qpointf(r.pos()); + int manualID = frame->manual_id; + for (const rj_common::UIRobot& r : frame->self) { + QPointF center = qpointf(r.position); bool faulty = false; - if (r.has_ball_sense_status() && (r.ball_sense_status() == rj_common::Dazzled || - r.ball_sense_status() == rj_common::Failed)) { - faulty = true; - } - if (r.has_kicker_works() && !r.kicker_works()) { - // faulty = true; - } - for (int i = 0; i < r.motor_status().size(); ++i) { - if (r.motor_status(i) != rj_common::Good) { + + for (int i = 0; i < r.motors.size(); ++i) { + if (r.motors.at(i) != rj_common::kGood) { faulty = true; } } - if (r.has_battery_voltage() && r.battery_voltage() <= 14.3f) { + if (r.battery <= 14.3f) { faulty = true; } - drawRobot(p, frame->blue_team(), r.shell(), center, r.angle(), - r.ball_sense_status() == rj_common::HasBall, faulty); + drawRobot(p, frame->blue, r.shell_id, center, r.heading, + r.has_ball, faulty); // Highlight the manually controlled robot - if (manualID == r.shell()) { + if (manualID == r.shell_id) { p.setPen(greenPen); const float r = kRobotRadius + .05; p.drawEllipse(center, r, r); @@ -458,20 +452,20 @@ void FieldView::drawTeamSpace(QPainter& p) { // Robot text QPointF textPos = center - rtX * 0.2 - rtY * (kRobotRadius + 0.1); - for (const DebugText& text : r.text()) { - if (text.layer() < 0 || layerVisible(text.layer())) { - tempPen.setColor(text.color()); + for (const DebugText& text : r.texts) { + if (text.layer < 0 || layerVisible(text.layer)) { + tempPen.setColor(text.color); p.setPen(tempPen); - drawText(p, textPos, QString::fromStdString(text.text()), false); + drawText(p, textPos, QString::fromStdString(text.text), false); textPos -= rtY * 0.1; } } } // Current ball position and velocity - if (frame->has_ball()) { - QPointF pos = qpointf(frame->ball().pos()); - QPointF vel = qpointf(frame->ball().vel()); + if (frame->ball_state.has_value()) { + QPointF pos = qpointf(frame->ball_state->position); + QPointF vel = qpointf(frame->ball_state->velocity); p.setPen(ballPen); p.setBrush(ballColor); @@ -517,7 +511,7 @@ void FieldView::drawCoords(QPainter& p) { drawText(p, QPointF(0.1, 0.25), "+Y"); } -void FieldView::drawField(QPainter& p, const rj_common::LiveFrame* frame) { +void FieldView::drawField(QPainter& p, const std::shared_ptr& frame) { p.save(); // reset to center @@ -583,7 +577,7 @@ void FieldView::drawField(QPainter& p, const rj_common::LiveFrame* frame) { float y[2] = {FieldDimensions::current_dimensions.goal_width() / 2.0f, -FieldDimensions::current_dimensions.goal_width() / 2.0f}; - bool flip = frame->blue_team() ^ frame->defend_plus_x(); + bool flip = frame->blue ^ frame->defend_plus_x; QColor goalColor = flip ? Qt::yellow : Qt::blue; p.setPen(QPen(goalColor, diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 07cad7c0b94..0cd22331069 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -74,7 +74,6 @@ MainWindow::MainWindow(Processor* processor, bool has_external_ref, QWidget* par qRegisterMetaType>("QVector"); _ui.setupUi(this); - _ui.fieldView->history(&_history); _ui.logTree->setVisible(false); _ui.logHistoryLocation->setVisible(false); @@ -319,9 +318,10 @@ void MainWindow::updateViews() { auto value = _ui.logHistoryLocation->value(); - std::shared_ptr live_frame; + std::shared_ptr ui_frame; // Grab frames + std::vector> history; { std::lock_guard lock(*context__mutex); if (context_->frames.empty()) { @@ -329,13 +329,13 @@ void MainWindow::updateViews() { return; } - live_frame = context_->frames.back(); + ui_frame = context_->frames.back(); + // Set the history vector by taking the last kHistorySize elements of the + // full context history, or fewer if context is shorter. + history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), + context_->frames.end()); } - - // // Set the history vector by taking the last kHistorySize elements of the - // // "long" history, or fewer if _longHistory is shorter. - _history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), - context_->frames.end()); + _ui.fieldView->setHistory(std::move(history)); // Update field view _ui.fieldView->update(); @@ -345,8 +345,8 @@ void MainWindow::updateViews() { // Check if any debug layers have been added // (layers should never be removed) - if (live_frame) { - updateDebugLayers(*live_frame); + if (ui_frame) { + updateDebugLayers(*ui_frame); } /**************************************************************************/ @@ -391,12 +391,12 @@ void MainWindow::updateViews() { /**************************************************************************/ /********************** Update robot status list **************************/ /**************************************************************************/ - if (live_frame != nullptr) { + if (ui_frame != nullptr) { // update robot status list for (size_t shell = 0; shell < kNumShells; shell++) { // Search for the corresponding references. auto maybe_rx = [&]() -> std::optional> { - for (auto& i : live_frame->radio_rx_) { + for (auto& i : ui_frame->radio_rx) { if (i.shell_id == shell) { return i; } @@ -404,10 +404,10 @@ void MainWindow::updateViews() { return std::nullopt; }(); auto maybe_robot = - [&]() -> std::optional> { - for (int i = 0; i < live_frame->self_size(); i++) { - if (live_frame->self(i).shell() == shell) { - return live_frame->self(i); + [&]() -> std::optional> { + for (int i = 0; i < ui_frame->self.size(); i++) { + if (ui_frame->self.at(i).shell_id == shell) { + return ui_frame->self.at(i); } } return std::nullopt; @@ -461,7 +461,7 @@ void MainWindow::updateViews() { } if (statusWidget != nullptr) { - statusWidget->load(rx, maybe_robot, live_frame->blue_team()); + statusWidget->load(rx, maybe_robot, ui_frame->blue); } } } @@ -894,10 +894,10 @@ void MainWindow::on_debugLayers_itemChanged(QListWidgetItem* item) { _ui.fieldView->update(); } -void MainWindow::updateDebugLayers(const rj_common::LiveFrame& frame) { - if (frame.debug_layers_size() > _ui.debugLayers->count()) { - for (int i = _ui.debugLayers->count(); i < frame.debug_layers_size(); ++i) { - const QString name = QString::fromStdString(frame.debug_layers(i)); +void MainWindow::updateDebugLayers(const rj_common::UIFrame& frame) { + if (frame.debug_draw_frame.debug_layers.size() > _ui.debugLayers->count()) { + for (int i = _ui.debugLayers->count(); i < frame.debug_draw_frame.debug_layers.size(); ++i) { + const QString name = QString::fromStdString(frame.debug_draw_frame.debug_layers.at(i)); bool enabled = !std::any_of(defaultHiddenLayers.begin(), defaultHiddenLayers.end(), [&](const QString& string) { return string == name; }); addLayer(i, name, enabled); diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index dd708fcb7ea..2866cb83216 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -109,7 +109,7 @@ void Processor::run() { std::lock_guard lock(loop_mutex_); debug_draw_sub_->run(); context_.debug_drawer.commit_frame(); - context_.frames.emplace_back(create_log_frame(context_)); + context_.frames.emplace_back(create_ui_frame(context_)); } //////////////// diff --git a/src/rj_ui/src/robot_status_widget.cpp b/src/rj_ui/src/robot_status_widget.cpp index 7e913e38196..10dbddd3b23 100644 --- a/src/rj_ui/src/robot_status_widget.cpp +++ b/src/rj_ui/src/robot_status_widget.cpp @@ -104,7 +104,7 @@ void RobotStatusWidget::setShowstopper(bool showstopper) { } void RobotStatusWidget::load(const RobotStatus& status, - const std::optional& maybe_robot, + const std::optional& maybe_robot, bool blueTeam) { setShellID(status.shell_id); setBlueTeam(blueTeam); diff --git a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp index e4fa2950856..e40abe91159 100644 --- a/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp +++ b/src/rj_ui/src/ros2_temp/debug_draw_interface.cpp @@ -38,11 +38,11 @@ void DebugDrawInterface::run() { } for (const auto& path : debug_draw->paths) { DebugRobotPath& debug_path = context_->debug_drawer.add_debug_path(); - debug_path.set_layer( - context_->debug_drawer.find_debug_layer(QString::fromStdString(layer))); + debug_path.layer = + context_->debug_drawer.find_debug_layer(QString::fromStdString(layer)); for (const auto& point : path.points) { - DebugRobotPath::DebugRobotPathPoint& new_point = debug_path.add_points(); - new_point.mutable_pos() = rj_geometry::Point(point.x, point.y); + DebugRobotPath::DebugRobotPathPoint& new_point = debug_path.points.emplace_back(); + new_point.pos = rj_geometry::Point(point.x, point.y); } } for (const auto& text : debug_draw->debug_text) { diff --git a/src/rj_ui/src/sim_field_view.cpp b/src/rj_ui/src/sim_field_view.cpp index e470a47293e..198d1167ed9 100644 --- a/src/rj_ui/src/sim_field_view.cpp +++ b/src/rj_ui/src/sim_field_view.cpp @@ -44,20 +44,20 @@ void SimFieldView::mousePressEvent(QMouseEvent* me) { rj_geometry::Point pos = _worldToTeam * _screenToWorld * me->pos(); - std::shared_ptr frame = currentFrame(); + std::shared_ptr frame = currentFrame(); if (me->button() == Qt::LeftButton && frame) { drag_robot_ = -1; - for (const rj_common::LiveFrame::Robot& r : frame->self()) { - if (pos.near_point(r.pos(), kRobotRadius)) { - drag_robot_ = r.shell(); - drag_robot_blue_ = frame->blue_team(); + for (const rj_common::UIRobot& r : frame->self) { + if (pos.near_point(r.position, kRobotRadius)) { + drag_robot_ = r.shell_id; + drag_robot_blue_ = frame->blue; break; } } - for (const rj_common::LiveFrame::Robot& r : frame->opp()) { - if (pos.near_point(r.pos(), kRobotRadius)) { - drag_robot_ = r.shell(); - drag_robot_blue_ = !frame->blue_team(); + for (const rj_common::UIRobot& r : frame->opp) { + if (pos.near_point(r.position, kRobotRadius)) { + drag_robot_ = r.shell_id; + drag_robot_blue_ = !frame->blue; break; } } @@ -68,21 +68,21 @@ void SimFieldView::mousePressEvent(QMouseEvent* me) { drag_mode_ = DRAG_PLACE; } else if (me->button() == Qt::RightButton && frame) { - if (frame->has_ball() && pos.near_point(frame->ball().pos(), 10 * kBallRadius)) { + if (frame->ball_state.has_value() && pos.near_point(frame->ball_state->position, 10 * kBallRadius)) { // Drag to shoot the ball drag_mode_ = DRAG_SHOOT; drag_point_ = pos; } else { // Look for a robot selection int new_id = -1; - for (int i = 0; i < frame->self_size(); ++i) { - if (pos.dist_to(frame->self(i).pos()) < kRobotRadius) { - new_id = frame->self(i).shell(); + for (int i = 0; i < frame->self.size(); ++i) { + if (pos.dist_to(frame->self.at(i).position) < kRobotRadius) { + new_id = frame->self.at(i).shell_id; break; } } - if (new_id != frame->manual_id()) { + if (new_id != frame->manual_id) { robotSelected(new_id); } } @@ -154,10 +154,10 @@ void SimFieldView::drawTeamSpace(QPainter& p) { FieldView::drawTeamSpace(p); // Simulator drag-to-shoot - std::shared_ptr frame = currentFrame(); - if (drag_mode_ == DRAG_SHOOT && frame) { + std::shared_ptr frame = currentFrame(); + if (drag_mode_ == DRAG_SHOOT && frame && frame->ball_state.has_value()) { p.setPen(QPen(Qt::white, 0.025f)); - rj_geometry::Point ball = frame->ball().pos(); + rj_geometry::Point ball = frame->ball_state->position; p.drawLine(ball.to_q_point_f(), drag_point_.to_q_point_f()); if (ball != drag_point_) { From 78be2130c102d26813531a9e36738839180ee2ec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 25 Sep 2026 21:13:52 -0400 Subject: [PATCH 08/21] Fix Code Style On sd/rm-logger (#2568) automated style fixes Co-authored-by: sanatd33 --- src/rj_common/include/rj_common/context.hpp | 9 ++++----- src/rj_common/include/rj_common/debug_drawings.hpp | 2 +- src/rj_common/include/rj_common/ui_frame.hpp | 12 ++---------- src/rj_ui/include/rj_ui/main_window.hpp | 2 +- src/rj_ui/include/rj_ui/processor.hpp | 2 +- src/rj_ui/include/rj_ui/robot_status_widget.hpp | 4 ++-- src/rj_ui/src/field_view.cpp | 10 ++++------ src/rj_ui/src/main_window.cpp | 5 +++-- src/rj_ui/src/robot_status_widget.cpp | 3 +-- src/rj_ui/src/sim_field_view.cpp | 3 ++- 10 files changed, 21 insertions(+), 31 deletions(-) diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 33bf0e01a3e..4fb55c9ea64 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -70,7 +70,7 @@ struct Context { }; inline rj_common::UIRobot create_ui_robot(int shell_id, const RobotState& state, - const std::optional& status) { + const std::optional& status) { rj_common::UIRobot out; out.shell_id = shell_id; @@ -81,9 +81,8 @@ inline rj_common::UIRobot create_ui_robot(int shell_id, const RobotState& state, out.has_ball = status->has_ball; out.motors.resize(5); for (int i = 0; i < 5; i++) { - out.motors.at(i) = - (status->motors_healthy[i] ? - rj_common::MotorStatus::kGood : rj_common::MotorStatus::kFault); + out.motors.at(i) = (status->motors_healthy[i] ? rj_common::MotorStatus::kGood + : rj_common::MotorStatus::kFault); } out.kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; out.battery = static_cast(status->battery_voltage); @@ -93,7 +92,7 @@ inline rj_common::UIRobot create_ui_robot(int shell_id, const RobotState& state, inline std::shared_ptr create_ui_frame(const Context& context) { auto frame = std::make_shared(); - + frame->debug_draw_frame = context.debug_drawer.published_frame(); frame->blue = context.blue_team; diff --git a/src/rj_common/include/rj_common/debug_drawings.hpp b/src/rj_common/include/rj_common/debug_drawings.hpp index f87c23f63d5..ca0fdef024b 100644 --- a/src/rj_common/include/rj_common/debug_drawings.hpp +++ b/src/rj_common/include/rj_common/debug_drawings.hpp @@ -16,7 +16,7 @@ struct DebugRobotPath { rj_geometry::Point pos; rj_geometry::Point vel; }; - + int layer = -1; std::vector points; }; diff --git a/src/rj_common/include/rj_common/ui_frame.hpp b/src/rj_common/include/rj_common/ui_frame.hpp index 0c9e76d0eca..9810fbbe90c 100644 --- a/src/rj_common/include/rj_common/ui_frame.hpp +++ b/src/rj_common/include/rj_common/ui_frame.hpp @@ -15,16 +15,8 @@ namespace rj_common { -enum BallSenseStatus { - kNoBall = 0, - kHasBall, - kDazzled, - kFailed -}; -enum MotorStatus { - kGood = 0, - kFault -}; +enum BallSenseStatus { kNoBall = 0, kHasBall, kDazzled, kFailed }; +enum MotorStatus { kGood = 0, kFault }; struct UIRobot { int shell_id = -1; diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 8789cac680f..87dafc5c461 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -248,7 +248,7 @@ private Q_SLOTS: std::mutex* context__mutex; Context* context_; - + // ROS Compatibility stuff void send_quick_command(const PlayState& state); diff --git a/src/rj_ui/include/rj_ui/processor.hpp b/src/rj_ui/include/rj_ui/processor.hpp index 8f0dc14cba5..812da871bff 100644 --- a/src/rj_ui/include/rj_ui/processor.hpp +++ b/src/rj_ui/include/rj_ui/processor.hpp @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/rj_ui/include/rj_ui/robot_status_widget.hpp b/src/rj_ui/include/rj_ui/robot_status_widget.hpp index 864be83b4aa..02567bc9a6f 100644 --- a/src/rj_ui/include/rj_ui/robot_status_widget.hpp +++ b/src/rj_ui/include/rj_ui/robot_status_widget.hpp @@ -24,8 +24,8 @@ class RobotStatusWidget : public QWidget { public: RobotStatusWidget(QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); - void load(const RobotStatus& status, - const std::optional& maybe_robot, bool blueTeam); + void load(const RobotStatus& status, const std::optional& maybe_robot, + bool blueTeam); [[nodiscard]] int shellID() const; void setShellID(int shellID); diff --git a/src/rj_ui/src/field_view.cpp b/src/rj_ui/src/field_view.cpp index 9b300caa411..618bd269c09 100644 --- a/src/rj_ui/src/field_view.cpp +++ b/src/rj_ui/src/field_view.cpp @@ -271,8 +271,8 @@ void FieldView::drawTeamSpace(QPainter& p) { const DebugRobotPath::DebugRobotPathPoint& to = path.points.at(i + 1); rj_geometry::Point avgVel = (rj_geometry::Point(path.points.at(i).vel) + - rj_geometry::Point(path.points.at(i + 1).vel)) / - 2; + rj_geometry::Point(path.points.at(i + 1).vel)) / + 2; auto pcntMaxSpd = static_cast(avgVel.mag() / planning::MotionConstraints{}.max_speed); QColor mixedColor(std::max(0, std::min((int)(255 * pcntMaxSpd), 255)), 0, @@ -419,8 +419,7 @@ void FieldView::drawTeamSpace(QPainter& p) { // Opponent robots for (const rj_common::UIRobot& r : frame->opp) { - drawRobot(p, !frame->blue, r.shell_id, qpointf(r.position), r.heading, - r.has_ball); + drawRobot(p, !frame->blue, r.shell_id, qpointf(r.position), r.heading, r.has_ball); } // Our robots @@ -439,8 +438,7 @@ void FieldView::drawTeamSpace(QPainter& p) { faulty = true; } - drawRobot(p, frame->blue, r.shell_id, center, r.heading, - r.has_ball, faulty); + drawRobot(p, frame->blue, r.shell_id, center, r.heading, r.has_ball, faulty); // Highlight the manually controlled robot if (manualID == r.shell_id) { diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 30f96cf850e..28f3c18a536 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -333,7 +333,7 @@ void MainWindow::updateViews() { // Set the history vector by taking the last kHistorySize elements of the // full context history, or fewer if context is shorter. history.assign(context_->frames.end() - std::min(kHistorySize, context_->frames.size()), - context_->frames.end()); + context_->frames.end()); } _ui.fieldView->setHistory(std::move(history)); @@ -896,7 +896,8 @@ void MainWindow::on_debugLayers_itemChanged(QListWidgetItem* item) { void MainWindow::updateDebugLayers(const rj_common::UIFrame& frame) { if (frame.debug_draw_frame.debug_layers.size() > _ui.debugLayers->count()) { - for (int i = _ui.debugLayers->count(); i < frame.debug_draw_frame.debug_layers.size(); ++i) { + for (int i = _ui.debugLayers->count(); i < frame.debug_draw_frame.debug_layers.size(); + ++i) { const QString name = QString::fromStdString(frame.debug_draw_frame.debug_layers.at(i)); bool enabled = !std::any_of(defaultHiddenLayers.begin(), defaultHiddenLayers.end(), [&](const QString& string) { return string == name; }); diff --git a/src/rj_ui/src/robot_status_widget.cpp b/src/rj_ui/src/robot_status_widget.cpp index 10dbddd3b23..7925e4ab051 100644 --- a/src/rj_ui/src/robot_status_widget.cpp +++ b/src/rj_ui/src/robot_status_widget.cpp @@ -104,8 +104,7 @@ void RobotStatusWidget::setShowstopper(bool showstopper) { } void RobotStatusWidget::load(const RobotStatus& status, - const std::optional& maybe_robot, - bool blueTeam) { + const std::optional& maybe_robot, bool blueTeam) { setShellID(status.shell_id); setBlueTeam(blueTeam); setRobotModel(status.version == RobotStatus::HardwareVersion::kSimulated ? "Simulation" diff --git a/src/rj_ui/src/sim_field_view.cpp b/src/rj_ui/src/sim_field_view.cpp index b66c884edc7..7defc35567a 100644 --- a/src/rj_ui/src/sim_field_view.cpp +++ b/src/rj_ui/src/sim_field_view.cpp @@ -67,7 +67,8 @@ void SimFieldView::mousePressEvent(QMouseEvent* me) { drag_mode_ = DRAG_PLACE; } else if (me->button() == Qt::RightButton && frame) { - if (frame->ball_state.has_value() && pos.near_point(frame->ball_state->position, 10 * kBallRadius)) { + if (frame->ball_state.has_value() && + pos.near_point(frame->ball_state->position, 10 * kBallRadius)) { // Drag to shoot the ball drag_mode_ = DRAG_SHOOT; drag_point_ = pos; From 4bea22e2cf8a18bcc226c2148fe9af35a3282763 Mon Sep 17 00:00:00 2001 From: rishiso Date: Sun, 27 Sep 2026 20:18:33 -0400 Subject: [PATCH 09/21] . --- src/rj_common/include/rj_common/context.hpp | 130 ++++++++---------- .../include/rj_common/debug_drawer.hpp | 6 +- src/rj_common/include/rj_common/ui_frame.hpp | 19 +++ src/rj_ui/src/processor.cpp | 2 +- 4 files changed, 77 insertions(+), 80 deletions(-) diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 4fb55c9ea64..9e2d0ed4eb0 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -18,8 +18,9 @@ #include "rj_common/ui_frame.hpp" #include "rj_common/world_state.hpp" -struct Context { - Context() : debug_drawer(this) {} +class Context { +public: + Context() {} // Delete copy, copy-assign, move, and move-assign because // many places are expected to hold Context* pointers. @@ -28,6 +29,59 @@ struct Context { Context(Context&&) = delete; Context& operator=(Context&&) = delete; + // Creates a UIFrame based on the current state of Context + // and adds it to the frames vector. + void create_ui_frame() { + auto frame = std::make_shared(); + + frame->debug_draw_frame = debug_drawer.published_frame(); + + frame->blue = blue_team; + + for (size_t shell = 0; shell < kNumShells; shell++) { + const auto& state = world_state.our_robots.at(shell); + const auto& status = robot_status.at(shell); + + if (RJ::now() - status.timestamp < RJ::Seconds(0.5)) { + frame->radio_rx.push_back(status); + } + + if (!state.visible) { + continue; + } + + frame->self.push_back(rj_common::UIRobot(shell, state, status)); + } + + for (size_t shell = 0; shell < kNumShells; shell++) { + const auto& state = world_state.their_robots.at(shell); + if (!state.visible) { + continue; + } + + frame->opp.push_back(rj_common::UIRobot(shell, state, std::nullopt)); + } + + if (world_state.ball.visible) { + frame->ball_state = {world_state.ball.position, world_state.ball.velocity}; + } + + frame->manual_id = game_settings.joystick_config.manual_id; + frame->defend_plus_x = game_settings.defend_plus_x; + frame->use_our_half = game_settings.use_our_half; + frame->use_their_half = game_settings.use_their_half; + + if (blue_team) { + frame->yellow_name = their_info.name; + frame->blue_name = our_info.name; + } else { + frame->yellow_name = our_info.name; + frame->blue_name = their_info.name; + } + + frames.push_back(frame); + } + // Gameplay -> Planning, Radio std::array robot_intents; // Motion control -> Radio @@ -68,75 +122,3 @@ struct Context { RJ::Time start_time; }; - -inline rj_common::UIRobot create_ui_robot(int shell_id, const RobotState& state, - const std::optional& status) { - rj_common::UIRobot out; - out.shell_id = shell_id; - - out.position = state.pose.position(); - out.heading = state.pose.heading(); - - if (status != std::nullopt) { - out.has_ball = status->has_ball; - out.motors.resize(5); - for (int i = 0; i < 5; i++) { - out.motors.at(i) = (status->motors_healthy[i] ? rj_common::MotorStatus::kGood - : rj_common::MotorStatus::kFault); - } - out.kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; - out.battery = static_cast(status->battery_voltage); - } - return out; -} - -inline std::shared_ptr create_ui_frame(const Context& context) { - auto frame = std::make_shared(); - - frame->debug_draw_frame = context.debug_drawer.published_frame(); - - frame->blue = context.blue_team; - - for (size_t shell = 0; shell < kNumShells; shell++) { - const auto& state = context.world_state.our_robots.at(shell); - const auto& status = context.robot_status.at(shell); - - if (RJ::now() - status.timestamp < RJ::Seconds(0.5)) { - frame->radio_rx.push_back(status); - } - - if (!state.visible) { - continue; - } - - frame->self.push_back(create_ui_robot(shell, state, status)); - } - - for (size_t shell = 0; shell < kNumShells; shell++) { - const auto& state = context.world_state.their_robots.at(shell); - if (!state.visible) { - continue; - } - - frame->opp.push_back(create_ui_robot(shell, state, std::nullopt)); - } - - if (context.world_state.ball.visible) { - frame->ball_state = {context.world_state.ball.position, context.world_state.ball.velocity}; - } - - frame->manual_id = context.game_settings.joystick_config.manual_id; - frame->defend_plus_x = context.game_settings.defend_plus_x; - frame->use_our_half = context.game_settings.use_our_half; - frame->use_their_half = context.game_settings.use_their_half; - - if (context.blue_team) { - frame->yellow_name = context.their_info.name; - frame->blue_name = context.our_info.name; - } else { - frame->yellow_name = context.our_info.name; - frame->blue_name = context.their_info.name; - } - - return frame; -} diff --git a/src/rj_common/include/rj_common/debug_drawer.hpp b/src/rj_common/include/rj_common/debug_drawer.hpp index 5c3bd344e16..9b347987cda 100644 --- a/src/rj_common/include/rj_common/debug_drawer.hpp +++ b/src/rj_common/include/rj_common/debug_drawer.hpp @@ -18,11 +18,9 @@ #include "rj_common/debug_drawings.hpp" -struct Context; - class DebugDrawer { public: - DebugDrawer(Context* context) : num_debug_layers_(0), context_(context) {} + DebugDrawer() : num_debug_layers_(0) {} const QStringList& debug_layers() const { return debug_layers_; } @@ -102,8 +100,6 @@ class DebugDrawer { /// Debug layers in order by ID QStringList debug_layers_; - Context* context_; - DebugDrawFrame current_; DebugDrawFrame published_; }; diff --git a/src/rj_common/include/rj_common/ui_frame.hpp b/src/rj_common/include/rj_common/ui_frame.hpp index 9810fbbe90c..0872186b500 100644 --- a/src/rj_common/include/rj_common/ui_frame.hpp +++ b/src/rj_common/include/rj_common/ui_frame.hpp @@ -19,6 +19,25 @@ enum BallSenseStatus { kNoBall = 0, kHasBall, kDazzled, kFailed }; enum MotorStatus { kGood = 0, kFault }; struct UIRobot { + UIRobot(int shell_id, const RobotState& state, + const std::optional& status) { + this->shell_id = shell_id; + + position = state.pose.position(); + heading = state.pose.heading(); + + if (status != std::nullopt) { + has_ball = status->has_ball; + motors.resize(5); + for (int i = 0; i < 5; i++) { + motors.at(i) = (status->motors_healthy[i] ? rj_common::MotorStatus::kGood + : rj_common::MotorStatus::kFault); + } + kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; + battery = static_cast(status->battery_voltage); + } + } + int shell_id = -1; rj_geometry::Point position; double heading = 0; diff --git a/src/rj_ui/src/processor.cpp b/src/rj_ui/src/processor.cpp index 2866cb83216..6647622bf6f 100644 --- a/src/rj_ui/src/processor.cpp +++ b/src/rj_ui/src/processor.cpp @@ -109,7 +109,7 @@ void Processor::run() { std::lock_guard lock(loop_mutex_); debug_draw_sub_->run(); context_.debug_drawer.commit_frame(); - context_.frames.emplace_back(create_ui_frame(context_)); + context_.create_ui_frame(); } //////////////// From c350df5376bd2623bf9170fad4ef8fe5503e16d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:20:45 -0400 Subject: [PATCH 10/21] Fix Code Style On sd/rm-logger (#2572) automated style fixes Co-authored-by: sanatd33 --- src/rj_common/include/rj_common/ui_frame.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/rj_common/include/rj_common/ui_frame.hpp b/src/rj_common/include/rj_common/ui_frame.hpp index 0872186b500..2cc547ccc59 100644 --- a/src/rj_common/include/rj_common/ui_frame.hpp +++ b/src/rj_common/include/rj_common/ui_frame.hpp @@ -19,8 +19,7 @@ enum BallSenseStatus { kNoBall = 0, kHasBall, kDazzled, kFailed }; enum MotorStatus { kGood = 0, kFault }; struct UIRobot { - UIRobot(int shell_id, const RobotState& state, - const std::optional& status) { + UIRobot(int shell_id, const RobotState& state, const std::optional& status) { this->shell_id = shell_id; position = state.pose.position(); @@ -31,7 +30,7 @@ struct UIRobot { motors.resize(5); for (int i = 0; i < 5; i++) { motors.at(i) = (status->motors_healthy[i] ? rj_common::MotorStatus::kGood - : rj_common::MotorStatus::kFault); + : rj_common::MotorStatus::kFault); } kicker_ok = status->kicker != RobotStatus::KickerState::kFailed; battery = static_cast(status->battery_voltage); From 0845e8ce54eab568720930bdeb694f08fdf8fcf1 Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 19:11:38 -0400 Subject: [PATCH 11/21] address_comments --- src/rj_common/include/rj_common/context.hpp | 10 +++++++++- src/rj_ui/src/main_window.cpp | 2 -- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 9e2d0ed4eb0..8e9d9a1892b 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -15,9 +15,12 @@ #include "rj_common/radio/robot_status.hpp" #include "rj_common/robot_intent.hpp" #include "rj_common/team_info.hpp" +#include "rj_common/time.hpp" #include "rj_common/ui_frame.hpp" #include "rj_common/world_state.hpp" +constexpr size_t kMaxLogFrames = 60 * 60 * 30; +constexpr RJ::Seconds kDropRobotThreshold = RJ::Seconds(0.5); class Context { public: Context() {} @@ -42,7 +45,8 @@ class Context { const auto& state = world_state.our_robots.at(shell); const auto& status = robot_status.at(shell); - if (RJ::now() - status.timestamp < RJ::Seconds(0.5)) { + // Only add the robot to the frame if it recently sent a radio packet + if (RJ::now() - status.timestamp < kDropRobotThreshold) { frame->radio_rx.push_back(status); } @@ -79,7 +83,11 @@ class Context { frame->blue_name = their_info.name; } + // Only store last 30 minutes of frames frames.push_back(frame); + if (frames.size() > kMaxLogFrames) { + frames.erase(frames.begin()); + } } // Gameplay -> Planning, Radio diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index 28f3c18a536..aa9fd6b2663 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -316,8 +316,6 @@ void MainWindow::updateViews() { _procFPS->setText(QString("Proc: %1 fps").arg(_processor->framerate(), 0, 'f', 1)); } - auto value = _ui.logHistoryLocation->value(); - std::shared_ptr ui_frame; // Grab frames From a72ccacf80a0dfae1cba5d66175ee6ba25b236c1 Mon Sep 17 00:00:00 2001 From: rishiso Date: Sun, 27 Sep 2026 21:55:13 -0400 Subject: [PATCH 12/21] . --- .gitmodules | 6 + src/rj_protos/protos/RadioTx.proto.legacy | 35 -- src/rj_protos/protos/grSim_Commands.proto | 22 - src/rj_protos/protos/grSim_Packet.proto | 8 - src/rj_protos/protos/grSim_Replacement.proto | 22 - src/rj_protos/protos/referee.proto | 243 -------- src/rj_protos/protos/ssl-game-controller | 1 + src/rj_protos/protos/ssl_gc_common.proto | 28 - src/rj_protos/protos/ssl_gc_game_event.proto | 603 ------------------- src/rj_protos/protos/ssl_gc_geometry.proto | 16 - src/rj_protos/ssl-game-controller | 1 + 11 files changed, 8 insertions(+), 977 deletions(-) delete mode 100644 src/rj_protos/protos/RadioTx.proto.legacy delete mode 100644 src/rj_protos/protos/grSim_Commands.proto delete mode 100644 src/rj_protos/protos/grSim_Packet.proto delete mode 100644 src/rj_protos/protos/grSim_Replacement.proto delete mode 100644 src/rj_protos/protos/referee.proto create mode 160000 src/rj_protos/protos/ssl-game-controller delete mode 100644 src/rj_protos/protos/ssl_gc_common.proto delete mode 100644 src/rj_protos/protos/ssl_gc_game_event.proto delete mode 100644 src/rj_protos/protos/ssl_gc_geometry.proto create mode 160000 src/rj_protos/ssl-game-controller diff --git a/.gitmodules b/.gitmodules index 7d4501b829e..c6db78d1d61 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "external/style-configs"] path = external/style-configs url = https://github.com/robojackets/style-configs +[submodule "src/rj_protos/protos/ssl-game-controller"] + path = src/rj_protos/protos/ssl-game-controller + url = https://github.com/RoboCup-SSL/ssl-game-controller.git +[submodule "src/rj_protos/ssl-game-controller"] + path = src/rj_protos/ssl-game-controller + url = https://github.com/RoboCup-SSL/ssl-game-controller.git diff --git a/src/rj_protos/protos/RadioTx.proto.legacy b/src/rj_protos/protos/RadioTx.proto.legacy deleted file mode 100644 index f2b94b73f78..00000000000 --- a/src/rj_protos/protos/RadioTx.proto.legacy +++ /dev/null @@ -1,35 +0,0 @@ -// Packet going out from control program to radio program -syntax="proto2"; - -message RadioTx -{ - message Robot - { - required uint32 robot_id = 1; - optional int32 dribbler = 2; - optional uint32 kick = 3; - optional bool use_chipper = 4; - - // Translational velocity in body coordinates, m/s - required float body_x = 6; - required float body_y = 7; - - // Angular velocity, rad/s - required float body_w = 8; - - optional float accel = 9; - optional float decel = 10; - - // measurement from the camera - optional Point position = 14; - optional float latency = 15; - - optional bool kick_immediate = 11; - - optional bool sing = 12; - optional bool anthem = 13; - } - - repeated Robot robots = 2; - optional uint32 sequence = 3; -} diff --git a/src/rj_protos/protos/grSim_Commands.proto b/src/rj_protos/protos/grSim_Commands.proto deleted file mode 100644 index a15b5f5b21f..00000000000 --- a/src/rj_protos/protos/grSim_Commands.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto2"; - -message grSim_Robot_Command { - required uint32 id = 1; - required float kickspeedx = 2; - required float kickspeedz = 3; - required float veltangent = 4; - required float velnormal = 5; - required float velangular = 6; - required bool spinner = 7; - required bool wheelsspeed = 8; - optional float wheel1 = 9; - optional float wheel2 = 10; - optional float wheel3 = 11; - optional float wheel4 = 12; -} - -message grSim_Commands { - required double timestamp = 1; - required bool isteamyellow = 2; - repeated grSim_Robot_Command robot_commands = 3; -} diff --git a/src/rj_protos/protos/grSim_Packet.proto b/src/rj_protos/protos/grSim_Packet.proto deleted file mode 100644 index 2c4e7acd065..00000000000 --- a/src/rj_protos/protos/grSim_Packet.proto +++ /dev/null @@ -1,8 +0,0 @@ -syntax = "proto2"; - -import "grSim_Commands.proto"; -import "grSim_Replacement.proto"; -message grSim_Packet { - optional grSim_Commands commands = 1; - optional grSim_Replacement replacement = 2; -} diff --git a/src/rj_protos/protos/grSim_Replacement.proto b/src/rj_protos/protos/grSim_Replacement.proto deleted file mode 100644 index 08944ca36db..00000000000 --- a/src/rj_protos/protos/grSim_Replacement.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto2"; - -message grSim_RobotReplacement { -required double x=1; -required double y=2; -required double dir=3; -required uint32 id=4; -required bool yellowteam=5; -optional bool turnon = 6; -} - -message grSim_BallReplacement { - optional double x = 1; - optional double y = 2; - optional double vx = 3; - optional double vy = 4; -} - -message grSim_Replacement { -optional grSim_BallReplacement ball=1; -repeated grSim_RobotReplacement robots=2; -} diff --git a/src/rj_protos/protos/referee.proto b/src/rj_protos/protos/referee.proto deleted file mode 100644 index 34409661088..00000000000 --- a/src/rj_protos/protos/referee.proto +++ /dev/null @@ -1,243 +0,0 @@ -syntax = "proto2"; - -option go_package = "github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"; - -import "ssl_gc_game_event.proto"; - -// Each UDP packet contains one of these messages. -message Referee { - // A random UUID of the source that is kept constant at the source while running - // If multiple sources are broadcasting to the same network, this id can be used to identify - // individual sources - optional string source_identifier = 18; - - // The match type is a meta information about the current match that helps to process the logs - // after a competition - optional MatchType match_type = 19 [default = UNKNOWN_MATCH]; - - // The UNIX timestamp when the packet was sent, in microseconds. - // Divide by 1,000,000 to get a time_t. - required uint64 packet_timestamp = 1; - - // These are the "coarse" stages of the game. - enum Stage { - // The first half is about to start. - // A kickoff is called within this stage. - // This stage ends with the NORMAL_START. - NORMAL_FIRST_HALF_PRE = 0; - // The first half of the normal game, before half time. - NORMAL_FIRST_HALF = 1; - // Half time between first and second halves. - NORMAL_HALF_TIME = 2; - // The second half is about to start. - // A kickoff is called within this stage. - // This stage ends with the NORMAL_START. - NORMAL_SECOND_HALF_PRE = 3; - // The second half of the normal game, after half time. - NORMAL_SECOND_HALF = 4; - // The break before extra time. - EXTRA_TIME_BREAK = 5; - // The first half of extra time is about to start. - // A kickoff is called within this stage. - // This stage ends with the NORMAL_START. - EXTRA_FIRST_HALF_PRE = 6; - // The first half of extra time. - EXTRA_FIRST_HALF = 7; - // Half time between first and second extra halves. - EXTRA_HALF_TIME = 8; - // The second half of extra time is about to start. - // A kickoff is called within this stage. - // This stage ends with the NORMAL_START. - EXTRA_SECOND_HALF_PRE = 9; - // The second half of extra time. - EXTRA_SECOND_HALF = 10; - // The break before penalty shootout. - PENALTY_SHOOTOUT_BREAK = 11; - // The penalty shootout. - PENALTY_SHOOTOUT = 12; - // The game is over. - POST_GAME = 13; - } - required Stage stage = 2; - - // The number of microseconds left in the stage. - // The following stages have this value; the rest do not: - // NORMAL_FIRST_HALF - // NORMAL_HALF_TIME - // NORMAL_SECOND_HALF - // EXTRA_TIME_BREAK - // EXTRA_FIRST_HALF - // EXTRA_HALF_TIME - // EXTRA_SECOND_HALF - // PENALTY_SHOOTOUT_BREAK - // - // If the stage runs over its specified time, this value - // becomes negative. - optional sint64 stage_time_left = 3; - - // These are the "fine" states of play on the field. - enum Command { - // All robots should completely stop moving. - HALT = 0; - // Robots must keep 50 cm from the ball. - STOP = 1; - // A prepared kickoff or penalty may now be taken. - NORMAL_START = 2; - // The ball is dropped and free for either team. - FORCE_START = 3; - // The yellow team may move into kickoff position. - PREPARE_KICKOFF_YELLOW = 4; - // The blue team may move into kickoff position. - PREPARE_KICKOFF_BLUE = 5; - // The yellow team may move into penalty position. - PREPARE_PENALTY_YELLOW = 6; - // The blue team may move into penalty position. - PREPARE_PENALTY_BLUE = 7; - // The yellow team may take a direct free kick. - DIRECT_FREE_YELLOW = 8; - // The blue team may take a direct free kick. - DIRECT_FREE_BLUE = 9; - // The yellow team may take an indirect free kick. - INDIRECT_FREE_YELLOW = 10 [deprecated = true]; - // The blue team may take an indirect free kick. - INDIRECT_FREE_BLUE = 11 [deprecated = true]; - // The yellow team is currently in a timeout. - TIMEOUT_YELLOW = 12; - // The blue team is currently in a timeout. - TIMEOUT_BLUE = 13; - // The yellow team just scored a goal. - // For information only. - // Deprecated: Use the score field from the team infos instead. That way, you can also - // detect revoked goals. - GOAL_YELLOW = 14 [deprecated = true]; - // The blue team just scored a goal. See also GOAL_YELLOW. - GOAL_BLUE = 15 [deprecated = true]; - // Equivalent to STOP, but the yellow team must pick up the ball and - // drop it in the Designated Position. - BALL_PLACEMENT_YELLOW = 16; - // Equivalent to STOP, but the blue team must pick up the ball and drop - // it in the Designated Position. - BALL_PLACEMENT_BLUE = 17; - } - required Command command = 4; - - // The number of commands issued since startup (mod 2^32). - required uint32 command_counter = 5; - - // The UNIX timestamp when the command was issued, in microseconds. - // This value changes only when a new command is issued, not on each packet. - required uint64 command_timestamp = 6; - - // Information about a single team. - message TeamInfo { - // The team's name (empty string if operator has not typed anything). - required string name = 1; - // The number of goals scored by the team during normal play and overtime. - required uint32 score = 2; - // The number of red cards issued to the team since the beginning of the game. - required uint32 red_cards = 3; - // The amount of time (in microseconds) left on each yellow card issued to the team. - // If no yellow cards are issued, this array has no elements. - // Otherwise, times are ordered from smallest to largest. - repeated uint32 yellow_card_times = 4 [packed = true]; - // The total number of yellow cards ever issued to the team. - required uint32 yellow_cards = 5; - // The number of timeouts this team can still call. - // If in a timeout right now, that timeout is excluded. - required uint32 timeouts = 6; - // The number of microseconds of timeout this team can use. - required uint32 timeout_time = 7; - // The pattern number of this team's goalkeeper. - required uint32 goalkeeper = 8; - // The total number of countable fouls that act towards yellow cards - optional uint32 foul_counter = 9; - // The number of consecutive ball placement failures of this team - optional uint32 ball_placement_failures = 10; - // Indicate if the team is able and allowed to place the ball - optional bool can_place_ball = 12; - // The maximum number of bots allowed on the field based on division and cards - optional uint32 max_allowed_bots = 13; - // The team has submitted an intent to substitute one or more robots at the next chance - optional bool bot_substitution_intent = 14; - // Indicate if the team reached the maximum allowed ball placement failures and is thus not - // allowed to place the ball anymore - optional bool ball_placement_failures_reached = 15; - // The team is allowed to substitute one or more robots currently - optional bool bot_substitution_allowed = 16; - // The number of bot substitutions left by the team in this halftime - optional uint32 bot_substitutions_left = 17; - // The number of microseconds left for current bot substitution - optional uint32 bot_substitution_time_left = 18; - } - - // Information about the two teams. - required TeamInfo yellow = 7; - required TeamInfo blue = 8; - - // The coordinates of the Designated Position. These are measured in - // millimetres and correspond to SSL-Vision coordinates. These fields are - // always either both present (in the case of a ball placement command) or - // both absent (in the case of any other command). - message Point { - required float x = 1; - required float y = 2; - } - optional Point designated_position = 9; - - // Information about the direction of play. - // True, if the blue team will have it's goal on the positive x-axis of the ssl-vision - // coordinate system. Obviously, the yellow team will play on the opposite half. - optional bool blue_team_on_positive_half = 10; - - // The game event that caused the referee command. - // deprecated in favor of game_events. - // optional Game_Event game_event = 11 [deprecated = true]; - reserved 11; - - // The command that will be issued after the current stoppage and ball placement to continue the - // game. - optional Command next_command = 12; - - // All game events that were detected since the last RUNNING state. - // Will be cleared as soon as the game is continued. - reserved 13; - repeated GameEvent game_events = 16; - - // All proposed game events that were detected since the last RUNNING state. - reserved 14; - repeated GameEventProposalGroup game_event_proposals = 17; - - // The time in microseconds that is remaining until the current action times out - // The time will not be reset. It can get negative. - // An autoRef would raise an appropriate event, if the time gets negative. - // Possible actions where this time is relevant: - // * free kicks - // * kickoff, penalty kick, force start - // * ball placement - optional int64 current_action_time_remaining = 15; - - // A message that can be displayed to the spectators, like a reason for a stoppage. - optional string status_message = 20; -} - -// List of matching proposals -message GameEventProposalGroup { - // Unique ID of this group - optional string id = 3; - // The proposed game events - repeated GameEvent game_events = 1; - // Whether the proposal group was accepted - optional bool accepted = 2; -} - -// MatchType is a meta information about the current match for easier log processing -enum MatchType { - // not set - UNKNOWN_MATCH = 0; - // match is part of the group phase - GROUP_PHASE = 1; - // match is part of the elimination phase - ELIMINATION_PHASE = 2; - // a friendly match, not part of a tournament - FRIENDLY = 3; -} \ No newline at end of file diff --git a/src/rj_protos/protos/ssl-game-controller b/src/rj_protos/protos/ssl-game-controller new file mode 160000 index 00000000000..b176f48c9aa --- /dev/null +++ b/src/rj_protos/protos/ssl-game-controller @@ -0,0 +1 @@ +Subproject commit b176f48c9aa2c1dbfdf4ee7bb39548630a734b91 diff --git a/src/rj_protos/protos/ssl_gc_common.proto b/src/rj_protos/protos/ssl_gc_common.proto deleted file mode 100644 index d117bc11281..00000000000 --- a/src/rj_protos/protos/ssl_gc_common.proto +++ /dev/null @@ -1,28 +0,0 @@ -syntax = "proto2"; - -option go_package = "github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"; - -// Team is either blue or yellow -enum Team { - // team not set - UNKNOWN = 0; - // yellow team - YELLOW = 1; - // blue team - BLUE = 2; -} - -// RobotId is the combination of a team and a robot id -message RobotId { - // the robot number - optional uint32 id = 1; - // the team that the robot belongs to - optional Team team = 2; -} - -// Division denotes the current division, which influences some rules -enum Division { - DIV_UNKNOWN = 0; - DIV_A = 1; - DIV_B = 2; -} \ No newline at end of file diff --git a/src/rj_protos/protos/ssl_gc_game_event.proto b/src/rj_protos/protos/ssl_gc_game_event.proto deleted file mode 100644 index 64200bda20e..00000000000 --- a/src/rj_protos/protos/ssl_gc_game_event.proto +++ /dev/null @@ -1,603 +0,0 @@ -syntax = "proto2"; - -option go_package = "github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"; - -import "ssl_gc_common.proto"; -import "ssl_gc_geometry.proto"; - -// GameEvent contains exactly one game event -// Each game event has optional and required fields. The required fields are mandatory to process -// the event. Some optional fields are only used for visualization, others are required to determine -// the ball placement position. If fields are missing that are required for the ball placement -// position, no ball placement command will be issued. Fields are marked optional to make testing -// and extending of the protocol easier. An autoRef should ideally set all fields, except if there -// are good reasons to not do so. -message GameEvent { - // A globally unique id of the game event. - optional string id = 50; - - // The type of the game event. - optional Type type = 40; - - // The origins of this game event. - // Empty, if it originates from game controller. - // Contains autoRef name(s), if it originates from one or more autoRefs. - // Ignored if sent by autoRef to game controller. - repeated string origin = 41; - - // Unix timestamp in microseconds when the event was created. - optional uint64 created_timestamp = 49; - - // the event that occurred - oneof event { - // Ball out of field events (stopping) - - BallLeftField ball_left_field_touch_line = 6; - BallLeftField ball_left_field_goal_line = 7; - AimlessKick aimless_kick = 11; - - // Stopping Fouls - - AttackerTooCloseToDefenseArea attacker_too_close_to_defense_area = 19; - DefenderInDefenseArea defender_in_defense_area = 31; - BoundaryCrossing boundary_crossing = 43; - KeeperHeldBall keeper_held_ball = 13; - BotDribbledBallTooFar bot_dribbled_ball_too_far = 17; - - BotPushedBot bot_pushed_bot = 24; - BotHeldBallDeliberately bot_held_ball_deliberately = 26; - BotTippedOver bot_tipped_over = 27; - BotDroppedParts bot_dropped_parts = 51; - - // Non-Stopping Fouls - - AttackerTouchedBallInDefenseArea attacker_touched_ball_in_defense_area = 15; - BotKickedBallTooFast bot_kicked_ball_too_fast = 18; - BotCrashUnique bot_crash_unique = 22; - BotCrashDrawn bot_crash_drawn = 21; - - // Fouls while ball out of play - - DefenderTooCloseToKickPoint defender_too_close_to_kick_point = 29; - BotTooFastInStop bot_too_fast_in_stop = 28; - BotInterferedPlacement bot_interfered_placement = 20; - - // Scoring goals - - Goal possible_goal = 39; - Goal goal = 8; - Goal invalid_goal = 44; - - // Other events - - AttackerDoubleTouchedBall attacker_double_touched_ball = 14; - PlacementSucceeded placement_succeeded = 5; - PenaltyKickFailed penalty_kick_failed = 45; - - NoProgressInGame no_progress_in_game = 2; - PlacementFailed placement_failed = 3; - MultipleCards multiple_cards = 32; - MultipleFouls multiple_fouls = 34; - BotSubstitution bot_substitution = 37; - ExcessiveBotSubstitution excessive_bot_substitution = 52; - TooManyRobots too_many_robots = 38; - ChallengeFlag challenge_flag = 46; - ChallengeFlagHandled challenge_flag_handled = 48; - EmergencyStop emergency_stop = 47; - - UnsportingBehaviorMinor unsporting_behavior_minor = 35; - UnsportingBehaviorMajor unsporting_behavior_major = 36; - - // Deprecated events - - // replaced by ready_to_continue flag - Prepared prepared = 1 [deprecated = true]; - // obsolete - IndirectGoal indirect_goal = 9 [deprecated = true]; - // replaced by the meta-information in the possible_goal event - ChippedGoal chipped_goal = 10 [deprecated = true]; - // obsolete - KickTimeout kick_timeout = 12 [deprecated = true]; - // rule removed - AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area = 16 - [deprecated = true]; - // obsolete - AttackerTouchedOpponentInDefenseArea attacker_touched_opponent_in_defense_area_skipped = 42 - [deprecated = true]; - // obsolete - BotCrashUnique bot_crash_unique_skipped = 23 [deprecated = true]; - // can not be used as long as autoRefs do not judge pushing - BotPushedBot bot_pushed_bot_skipped = 25 [deprecated = true]; - // rule removed - DefenderInDefenseAreaPartially defender_in_defense_area_partially = 30 [deprecated = true]; - // the referee msg already indicates this - MultiplePlacementFailures multiple_placement_failures = 33 [deprecated = true]; - } - - // the ball left the field normally - message BallLeftField { - // the team that last touched the ball - required Team by_team = 1; - // the bot that last touched the ball - optional uint32 by_bot = 2; - // the location where the ball left the field [m] - optional Vector2 location = 3; - } - // the ball left the field via goal line and a team committed an aimless kick - message AimlessKick { - // the team that last touched the ball - required Team by_team = 1; - // the bot that last touched the ball - optional uint32 by_bot = 2; - // the location where the ball left the field [m] - optional Vector2 location = 3; - // the location where the ball was last touched [m] - optional Vector2 kick_location = 4; - } - // a team shot a goal - message Goal { - // the team that scored the goal - required Team by_team = 1; - // the team that shot the goal (different from by_team for own goals) - optional Team kicking_team = 6; - // the bot that shot the goal - optional uint32 kicking_bot = 2; - // the location where the ball entered the goal [m] - optional Vector2 location = 3; - // the location where the ball was kicked (for deciding if this was a valid goal) [m] - optional Vector2 kick_location = 4; - // the maximum height the ball reached during the goal kick (for deciding if this was a - // valid goal) [m] - optional float max_ball_height = 5; - // number of robots of scoring team when the ball entered the goal (for deciding if this was - // a valid goal) - optional uint32 num_robots_by_team = 7; - // The UNIX timestamp [μs] when the scoring team last touched the ball - optional uint64 last_touch_by_team = 8; - // An additional message with e.g. a reason for invalid goals - optional string message = 9; - } - // the ball entered the goal directly during an indirect free kick - message IndirectGoal { - // the team that tried to shoot the goal - required Team by_team = 1; - // the bot that kicked the ball - at least the team must be set - optional uint32 by_bot = 2; - // the location where the ball entered the goal [m] - optional Vector2 location = 3; - // the location where the ball was kicked [m] - optional Vector2 kick_location = 4; - } - // the ball entered the goal, but was initially chipped - message ChippedGoal { - // the team that tried to shoot the goal - required Team by_team = 1; - // the bot that kicked the ball - optional uint32 by_bot = 2; - // the location where the ball entered the goal [m] - optional Vector2 location = 3; - // the location where the ball was kicked [m] - optional Vector2 kick_location = 4; - // the maximum height [m] of the ball, before it entered the goal and since the last kick - // [m] - optional float max_ball_height = 5; - } - // a bot moved too fast while the game was stopped - message BotTooFastInStop { - // the team that found guilty - required Team by_team = 1; - // the bot that was too fast - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the bot speed [m/s] - optional float speed = 4; - } - // a bot of the defending team got too close to the kick point during a free kick - message DefenderTooCloseToKickPoint { - // the team that was found guilty - required Team by_team = 1; - // the bot that violates the distance to the kick point - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the distance [m] from bot to the kick point (including the minimum radius) - optional float distance = 4; - } - // two robots crashed into each other with similar speeds - message BotCrashDrawn { - // the bot of the yellow team - optional uint32 bot_yellow = 1; - // the bot of the blue team - optional uint32 bot_blue = 2; - // the location of the crash (center between both bots) [m] - optional Vector2 location = 3; - // the calculated crash speed [m/s] of the two bots - optional float crash_speed = 4; - // the difference [m/s] of the velocity of the two bots - optional float speed_diff = 5; - // the angle [rad] in the range [0, π] of the bot velocity vectors - // an angle of 0 rad ( 0°) means, the bots barely touched each other - // an angle of π rad (180°) means, the bots crashed frontal into each other - optional float crash_angle = 6; - } - // two robots crashed into each other and one team was found guilty to due significant speed - // difference - message BotCrashUnique { - // the team that caused the crash - required Team by_team = 1; - // the bot that caused the crash - optional uint32 violator = 2; - // the bot of the opposite team that was involved in the crash - optional uint32 victim = 3; - // the location of the crash (center between both bots) [m] - optional Vector2 location = 4; - // the calculated crash speed vector [m/s] of the two bots - optional float crash_speed = 5; - // the difference [m/s] of the velocity of the two bots - optional float speed_diff = 6; - // the angle [rad] in the range [0, π] of the bot velocity vectors - // an angle of 0 rad ( 0°) means, the bots barely touched each other - // an angle of π rad (180°) means, the bots crashed frontal into each other - optional float crash_angle = 7; - } - // a bot pushed another bot over a significant distance - message BotPushedBot { - // the team that pushed the other team - required Team by_team = 1; - // the bot that pushed the other bot - optional uint32 violator = 2; - // the bot of the opposite team that was pushed - optional uint32 victim = 3; - // the location of the push (center between both bots) [m] - optional Vector2 location = 4; - // the pushed distance [m] - optional float pushed_distance = 5; - } - // a bot tipped over - message BotTippedOver { - // the team that found guilty - required Team by_team = 1; - // the bot that tipped over - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the location of the ball at the moment when this foul occurred [m] - optional Vector2 ball_location = 4; - } - // a bot dropped parts - message BotDroppedParts { - // the team that found guilty - required Team by_team = 1; - // the bot that dropped the parts - optional uint32 by_bot = 2; - // the location where the parts were dropped [m] - optional Vector2 location = 3; - // the location of the ball at the moment when this foul occurred [m] - optional Vector2 ball_location = 4; - } - // a defender other than the keeper was fully located inside its own defense and touched the - // ball - message DefenderInDefenseArea { - // the team that found guilty - required Team by_team = 1; - // the bot that is inside the penalty area - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the distance [m] from bot case to the nearest point outside the defense area - optional float distance = 4; - } - // a defender other than the keeper was partially located inside its own defense area and - // touched the ball - message DefenderInDefenseAreaPartially { - // the team that found guilty - required Team by_team = 1; - // the bot that is partially inside the penalty area - optional uint32 by_bot = 2; - // the location of the bot - optional Vector2 location = 3; - // the distance [m] that the bot is inside the penalty area - optional float distance = 4; - // the location of the ball at the moment when this foul occurred [m] - optional Vector2 ball_location = 5; - } - // an attacker touched the ball inside the opponent defense area - message AttackerTouchedBallInDefenseArea { - // the team that found guilty - required Team by_team = 1; - // the bot that is inside the penalty area - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the distance [m] that the bot is inside the penalty area - optional float distance = 4; - } - // a bot kicked the ball too fast - message BotKickedBallTooFast { - // the team that found guilty - required Team by_team = 1; - // the bot that kicked too fast - optional uint32 by_bot = 2; - // the location of the ball at the time of the highest speed [m] - optional Vector2 location = 3; - // the absolute initial ball speed (kick speed) [m/s] - optional float initial_ball_speed = 4; - // was the ball chipped? - optional bool chipped = 5; - } - // a bot dribbled to ball too far - message BotDribbledBallTooFar { - // the team that found guilty - required Team by_team = 1; - // the bot that dribbled too far - optional uint32 by_bot = 2; - // the location where the dribbling started [m] - optional Vector2 start = 3; - // the location where the maximum dribbling distance was reached [m] - optional Vector2 end = 4; - } - // an attacker touched the opponent robot inside defense area - message AttackerTouchedOpponentInDefenseArea { - // the team that found guilty - required Team by_team = 1; - // the bot that touched the opponent robot - optional uint32 by_bot = 2; - // the bot of the opposite team that was touched - optional uint32 victim = 4; - // the location of the contact point between both bots [m] - optional Vector2 location = 3; - } - // an attacker touched the ball multiple times when it was not allowed to - message AttackerDoubleTouchedBall { - // the team that found guilty - required Team by_team = 1; - // the bot that touched the ball twice - optional uint32 by_bot = 2; - // the location of the ball when it was first touched [m] - optional Vector2 location = 3; - } - // an attacker was located too near to the opponent defense area during stop or free kick - message AttackerTooCloseToDefenseArea { - // the team that found guilty - required Team by_team = 1; - // the bot that is too close to the defense area - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - // the distance [m] of the bot to the penalty area - optional float distance = 4; - // the location of the ball at the moment when this foul occurred [m] - optional Vector2 ball_location = 5; - } - // a bot held the ball for too long - message BotHeldBallDeliberately { - // the team that found guilty - required Team by_team = 1; - // the bot that holds the ball - optional uint32 by_bot = 2; - // the location of the ball [m] - optional Vector2 location = 3; - // the duration [s] that the bot hold the ball - optional float duration = 4; - } - // a bot interfered the ball placement of the other team - message BotInterferedPlacement { - // the team that found guilty - required Team by_team = 1; - // the bot that interfered the placement - optional uint32 by_bot = 2; - // the location of the bot [m] - optional Vector2 location = 3; - } - // a team collected multiple yellow cards - message MultipleCards { - // the team that received multiple yellow cards - required Team by_team = 1; - } - // a team collected multiple fouls, which results in a yellow card - message MultipleFouls { - // the team that collected multiple fouls - required Team by_team = 1; - // the list of game events that caused the multiple fouls - repeated GameEvent caused_game_events = 2; - } - // a team failed to place the ball multiple times in a row - message MultiplePlacementFailures { - // the team that failed multiple times - required Team by_team = 1; - } - // timeout waiting for the attacking team to perform the free kick - message KickTimeout { - // the team that that should have kicked - required Team by_team = 1; - // the location of the ball [m] - optional Vector2 location = 2; - // the time [s] that was waited - optional float time = 3; - } - // game was stuck - message NoProgressInGame { - // the location of the ball - optional Vector2 location = 1; - // the time [s] that was waited - optional float time = 2; - } - // ball placement failed - message PlacementFailed { - // the team that failed - required Team by_team = 1; - // the remaining distance [m] from ball to placement position - optional float remaining_distance = 2; - // the distance [m] of the nearest own robot to the ball - optional float nearest_own_bot_distance = 3; - } - // a team was found guilty for minor unsporting behavior - message UnsportingBehaviorMinor { - // the team that found guilty - required Team by_team = 1; - // an explanation of the situation and decision - required string reason = 2; - } - // a team was found guilty for major unsporting behavior - message UnsportingBehaviorMajor { - // the team that found guilty - required Team by_team = 1; - // an explanation of the situation and decision - required string reason = 2; - } - // a keeper held the ball in its defense area for too long - message KeeperHeldBall { - // the team that found guilty - required Team by_team = 1; - // the location of the ball [m] - optional Vector2 location = 2; - // the duration [s] that the keeper hold the ball - optional float duration = 3; - } - // a team successfully placed the ball - message PlacementSucceeded { - // the team that did the placement - required Team by_team = 1; - // the time [s] taken for placing the ball - optional float time_taken = 2; - // the distance [m] between placement location and actual ball position - optional float precision = 3; - // the distance [m] between the initial ball location and the placement position - optional float distance = 4; - } - // both teams are prepared - all conditions are met to continue (with kickoff or penalty kick) - message Prepared { - // the time [s] taken for preparing - optional float time_taken = 1; - } - // bots are being substituted by a team - message BotSubstitution { - // the team that substitutes robots - required Team by_team = 1; - } - // A foul for excessive bot substitutions - message ExcessiveBotSubstitution { - // the team that substitutes robots - required Team by_team = 1; - } - // A challenge flag, requested by a team previously, is flagged - message ChallengeFlag { - // the team that requested the challenge flag - required Team by_team = 1; - } - // A challenge, flagged recently, has been handled by the referee - message ChallengeFlagHandled { - // the team that requested the challenge flag - required Team by_team = 1; - // the challenge was accepted by the referee - required bool accepted = 2; - } - // An emergency stop, requested by team previously, occurred - message EmergencyStop { - // the team that substitutes robots - required Team by_team = 1; - } - // a team has too many robots on the field - message TooManyRobots { - // the team that has too many robots - required Team by_team = 1; - // number of robots allowed at the moment - optional int32 num_robots_allowed = 2; - // number of robots currently on the field - optional int32 num_robots_on_field = 3; - // the location of the ball at the moment when this foul occurred [m] - optional Vector2 ball_location = 4; - } - // a robot chipped the ball over the field boundary out of the playing surface - message BoundaryCrossing { - // the team that has too many robots - required Team by_team = 1; - // the location of the ball [m] - optional Vector2 location = 2; - } - // the penalty kick failed (by time or by keeper) - message PenaltyKickFailed { - // the team that last touched the ball - required Team by_team = 1; - // the location of the ball at the moment of this event [m] - optional Vector2 location = 2; - // an explanation of the failure - optional string reason = 3; - } - - enum Type { - UNKNOWN_GAME_EVENT_TYPE = 0; - - // Ball out of field events (stopping) - - BALL_LEFT_FIELD_TOUCH_LINE = 6; // triggered by autoRef - BALL_LEFT_FIELD_GOAL_LINE = 7; // triggered by autoRef - AIMLESS_KICK = 11; // triggered by autoRef - - // Stopping Fouls - - ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA = 19; // triggered by autoRef - DEFENDER_IN_DEFENSE_AREA = 31; // triggered by autoRef - BOUNDARY_CROSSING = 41; // triggered by autoRef - KEEPER_HELD_BALL = 13; // triggered by GC - BOT_DRIBBLED_BALL_TOO_FAR = 17; // triggered by autoRef - - BOT_PUSHED_BOT = 24; // triggered by human ref - BOT_HELD_BALL_DELIBERATELY = 26; // triggered by human ref - BOT_TIPPED_OVER = 27; // triggered by human ref - BOT_DROPPED_PARTS = 47; // triggered by human ref - - // Non-Stopping Fouls - - ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA = 15; // triggered by autoRef - BOT_KICKED_BALL_TOO_FAST = 18; // triggered by autoRef - BOT_CRASH_UNIQUE = 22; // triggered by autoRef - BOT_CRASH_DRAWN = 21; // triggered by autoRef - - // Fouls while ball out of play - - DEFENDER_TOO_CLOSE_TO_KICK_POINT = 29; // triggered by autoRef - BOT_TOO_FAST_IN_STOP = 28; // triggered by autoRef - BOT_INTERFERED_PLACEMENT = 20; // triggered by autoRef - EXCESSIVE_BOT_SUBSTITUTION = 48; // triggered by GC - - // Scoring goals - - POSSIBLE_GOAL = 39; // triggered by autoRef - GOAL = 8; // triggered by GC - INVALID_GOAL = 42; // triggered by GC - - // Other events - - ATTACKER_DOUBLE_TOUCHED_BALL = 14; // triggered by autoRef - PLACEMENT_SUCCEEDED = 5; // triggered by autoRef - PENALTY_KICK_FAILED = 43; // triggered by GC and autoRef - - NO_PROGRESS_IN_GAME = 2; // triggered by GC - PLACEMENT_FAILED = 3; // triggered by GC - MULTIPLE_CARDS = 32; // triggered by GC - MULTIPLE_FOULS = 34; // triggered by GC - BOT_SUBSTITUTION = 37; // triggered by GC - TOO_MANY_ROBOTS = 38; // triggered by GC - CHALLENGE_FLAG = 44; // triggered by GC - CHALLENGE_FLAG_HANDLED = 46; // triggered by GC - EMERGENCY_STOP = 45; // triggered by GC - - UNSPORTING_BEHAVIOR_MINOR = 35; // triggered by human ref - UNSPORTING_BEHAVIOR_MAJOR = 36; // triggered by human ref - - // Deprecated events - - PREPARED = 1 [deprecated = true]; - INDIRECT_GOAL = 9 [deprecated = true]; - CHIPPED_GOAL = 10 [deprecated = true]; - KICK_TIMEOUT = 12 [deprecated = true]; - ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA = 16 [deprecated = true]; - ATTACKER_TOUCHED_OPPONENT_IN_DEFENSE_AREA_SKIPPED = 40 [deprecated = true]; - BOT_CRASH_UNIQUE_SKIPPED = 23 [deprecated = true]; - BOT_PUSHED_BOT_SKIPPED = 25 [deprecated = true]; - DEFENDER_IN_DEFENSE_AREA_PARTIALLY = 30 [deprecated = true]; - MULTIPLE_PLACEMENT_FAILURES = 33 [deprecated = true]; - } -} \ No newline at end of file diff --git a/src/rj_protos/protos/ssl_gc_geometry.proto b/src/rj_protos/protos/ssl_gc_geometry.proto deleted file mode 100644 index 61c65771ae2..00000000000 --- a/src/rj_protos/protos/ssl_gc_geometry.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto2"; - -option go_package = "github.com/RoboCup-SSL/ssl-game-controller/internal/app/geom"; - -// A vector with two dimensions -message Vector2 { - required float x = 1; - required float y = 2; -} - -// A vector with three dimensions -message Vector3 { - required float x = 1; - required float y = 2; - required float z = 3; -} \ No newline at end of file diff --git a/src/rj_protos/ssl-game-controller b/src/rj_protos/ssl-game-controller new file mode 160000 index 00000000000..b176f48c9aa --- /dev/null +++ b/src/rj_protos/ssl-game-controller @@ -0,0 +1 @@ +Subproject commit b176f48c9aa2c1dbfdf4ee7bb39548630a734b91 From 432916d40e399ff9187c64fe60ebf6c3d43b53d0 Mon Sep 17 00:00:00 2001 From: Sanat Dhanyamraju Date: Mon, 28 Sep 2026 13:32:19 -0400 Subject: [PATCH 13/21] / --- .gitmodules | 6 +- src/rj_common/include/rj_common/context.hpp | 2 +- .../include/rj_common/referee_enums.hpp | 2 +- src/rj_common/include/rj_common/team_info.hpp | 2 +- src/rj_protos/CMakeLists.txt | 122 ++++++++++++---- src/rj_protos/protos/ssl-game-controller | 1 - .../protos/ssl_simulation_config.proto | 77 ----------- .../protos/ssl_simulation_control.proto | 73 ---------- .../protos/ssl_simulation_error.proto | 10 -- .../protos/ssl_simulation_robot_control.proto | 66 --------- .../ssl_simulation_robot_feedback.proto | 23 ---- .../protos/ssl_simulation_synchronous.proto | 25 ---- .../protos/ssl_vision_detection.proto | 33 ----- .../protos/ssl_vision_geometry.proto | 130 ------------------ src/rj_protos/protos/ssl_vision_wrapper.proto | 9 -- src/rj_protos/ssl-simulation-protocol | 1 + src/rj_radio/src/sim_radio.cpp | 2 +- .../include/rj_referee/external_referee.hpp | 2 +- src/rj_ui/include/rj_ui/main_window.hpp | 2 - src/rj_ui/include/rj_ui/sim_field_view.hpp | 3 - src/rj_ui/src/main_window.cpp | 2 - src/rj_ui/src/sim_field_view.cpp | 3 - src/rj_utils/include/rj_utils/conversions.hpp | 3 +- .../stamped_wrapper_packet.hpp | 2 +- .../rj_vision_receiver/vision_receiver.hpp | 2 +- 25 files changed, 105 insertions(+), 498 deletions(-) delete mode 160000 src/rj_protos/protos/ssl-game-controller delete mode 100644 src/rj_protos/protos/ssl_simulation_config.proto delete mode 100644 src/rj_protos/protos/ssl_simulation_control.proto delete mode 100644 src/rj_protos/protos/ssl_simulation_error.proto delete mode 100644 src/rj_protos/protos/ssl_simulation_robot_control.proto delete mode 100644 src/rj_protos/protos/ssl_simulation_robot_feedback.proto delete mode 100644 src/rj_protos/protos/ssl_simulation_synchronous.proto delete mode 100644 src/rj_protos/protos/ssl_vision_detection.proto delete mode 100644 src/rj_protos/protos/ssl_vision_geometry.proto delete mode 100644 src/rj_protos/protos/ssl_vision_wrapper.proto create mode 160000 src/rj_protos/ssl-simulation-protocol diff --git a/.gitmodules b/.gitmodules index c6db78d1d61..7506af86ac4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "external/style-configs"] path = external/style-configs url = https://github.com/robojackets/style-configs -[submodule "src/rj_protos/protos/ssl-game-controller"] - path = src/rj_protos/protos/ssl-game-controller - url = https://github.com/RoboCup-SSL/ssl-game-controller.git [submodule "src/rj_protos/ssl-game-controller"] path = src/rj_protos/ssl-game-controller url = https://github.com/RoboCup-SSL/ssl-game-controller.git +[submodule "src/rj_protos/ssl-simulation-protocol"] + path = src/rj_protos/ssl-simulation-protocol + url = https://github.com/RoboCup-SSL/ssl-simulation-protocol.git diff --git a/src/rj_common/include/rj_common/context.hpp b/src/rj_common/include/rj_common/context.hpp index 8e9d9a1892b..74d0c2f57b7 100644 --- a/src/rj_common/include/rj_common/context.hpp +++ b/src/rj_common/include/rj_common/context.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include "rj_common/control/motion_setpoint.hpp" #include "rj_common/debug_drawer.hpp" diff --git a/src/rj_common/include/rj_common/referee_enums.hpp b/src/rj_common/include/rj_common/referee_enums.hpp index 57e1cf67490..08682c8d78d 100644 --- a/src/rj_common/include/rj_common/referee_enums.hpp +++ b/src/rj_common/include/rj_common/referee_enums.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/src/rj_common/include/rj_common/team_info.hpp b/src/rj_common/include/rj_common/team_info.hpp index d95df344c80..542d087413c 100644 --- a/src/rj_common/include/rj_common/team_info.hpp +++ b/src/rj_common/include/rj_common/team_info.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/src/rj_protos/CMakeLists.txt b/src/rj_protos/CMakeLists.txt index 452cd778ceb..094a75a9ef4 100644 --- a/src/rj_protos/CMakeLists.txt +++ b/src/rj_protos/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.20) project(rj_protos LANGUAGES CXX) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -8,50 +8,113 @@ endif() find_package(ament_cmake REQUIRED) find_package(Protobuf REQUIRED) -protobuf_generate_cpp( - PROTOBUF_SRCS - PROTOBUF_HDRS - protos/grSim_Commands.proto - protos/grSim_Packet.proto - protos/grSim_Replacement.proto - protos/referee.proto - protos/ssl_gc_common.proto - protos/ssl_gc_geometry.proto - protos/ssl_gc_game_event.proto - protos/ssl_simulation_config.proto - protos/ssl_simulation_control.proto - protos/ssl_simulation_error.proto - protos/ssl_simulation_robot_control.proto - protos/ssl_simulation_robot_feedback.proto - protos/ssl_simulation_synchronous.proto - protos/ssl_vision_detection.proto - protos/ssl_vision_geometry.proto - protos/ssl_vision_wrapper.proto +set(GC_PROTO_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/ssl-game-controller/proto) +set(SIM_PROTO_SRC ${CMAKE_CURRENT_SOURCE_DIR}/ssl-simulation-protocol/proto) +set(SIM_PROTO_ROOT ${CMAKE_CURRENT_BINARY_DIR}/sim_proto) +set(GEN_ROOT ${CMAKE_CURRENT_BINARY_DIR}/gen) +set(GEN_DIR ${GEN_ROOT}/rj_protos) + +set(GC_PROTOS + state/ssl_gc_common.proto + state/ssl_gc_game_event.proto + state/ssl_gc_referee_message.proto + geom/ssl_gc_geometry.proto + vision/ssl_vision_detection.proto + vision/ssl_vision_geometry.proto + vision/ssl_vision_wrapper.proto +) + +set(SIM_PROTOS + ssl_simulation_config.proto + ssl_simulation_control.proto + ssl_simulation_error.proto + ssl_simulation_robot_control.proto + ssl_simulation_robot_feedback.proto + ssl_simulation_synchronous.proto ) +# ssl-simulation-protocol vendors its own flat copies of ssl_gc_common and +# ssl_vision_{detection,geometry}. Protobuf identifies files by import path, so +# compiling both copies would define RobotId etc. twice. Stage the sim protos +# with those imports pointed at the ssl-game-controller files instead; the +# submodule itself is left untouched. +set(SIM_IMPORT_REWRITES + "ssl_gc_common.proto" "state/ssl_gc_common.proto" + "ssl_vision_detection.proto" "vision/ssl_vision_detection.proto" + "ssl_vision_geometry.proto" "vision/ssl_vision_geometry.proto" +) + +foreach(proto ${SIM_PROTOS}) + file(READ ${SIM_PROTO_SRC}/${proto} content) + set(rewrites ${SIM_IMPORT_REWRITES}) + while(rewrites) + list(POP_FRONT rewrites from to) + string(REPLACE "import \"${from}\";" "import \"${to}\";" content "${content}") + endwhile() + file(CONFIGURE OUTPUT ${SIM_PROTO_ROOT}/${proto} CONTENT "${content}" @ONLY) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SIM_PROTO_SRC}/${proto}) +endforeach() + +set(PROTO_FILES) +foreach(proto ${GC_PROTOS}) + list(APPEND PROTO_FILES ${GC_PROTO_ROOT}/${proto}) +endforeach() +foreach(proto ${SIM_PROTOS}) + list(APPEND PROTO_FILES ${SIM_PROTO_ROOT}/${proto}) +endforeach() + +set(PROTO_SRCS) +set(PROTO_HDRS) +foreach(proto ${GC_PROTOS} ${SIM_PROTOS}) + string(REGEX REPLACE "\\.proto$" "" proto_base ${proto}) + set(proto_src ${GEN_DIR}/${proto_base}.pb.cc) + set(proto_hdr ${GEN_DIR}/${proto_base}.pb.h) + if(proto IN_LIST GC_PROTOS) + set(proto_file ${GC_PROTO_ROOT}/${proto}) + else() + set(proto_file ${SIM_PROTO_ROOT}/${proto}) + endif() + add_custom_command( + OUTPUT ${proto_src} ${proto_hdr} + COMMAND ${CMAKE_COMMAND} -E make_directory ${GEN_DIR} + COMMAND protobuf::protoc + --cpp_out=${GEN_DIR} + -I ${GC_PROTO_ROOT} + -I ${SIM_PROTO_ROOT} + ${proto_file} + DEPENDS ${PROTO_FILES} protobuf::protoc + COMMENT "Running C++ protocol buffer compiler on ${proto}" + VERBATIM + ) + list(APPEND PROTO_SRCS ${proto_src}) + list(APPEND PROTO_HDRS ${proto_hdr}) +endforeach() + add_library(${PROJECT_NAME} SHARED - ${PROTOBUF_HDRS} - ${PROTOBUF_SRCS} + ${PROTO_SRCS} + ${PROTO_HDRS} ) target_link_libraries(${PROJECT_NAME} protobuf::libprotobuf ) +# Consumers include ; generated code includes e.g. +# "state/ssl_gc_common.pb.h", so the rj_protos dir itself is also needed. target_include_directories(${PROJECT_NAME} - INTERFACE - $ + PUBLIC + $ + $ $ + $ ) target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated-declarations) -ament_export_targets(${PROJECT_NAME} HAS_LIBRARY_TARGET) -ament_export_dependencies(Protobuf) - install( - DIRECTORY ${CMAKE_BINARY_DIR} + DIRECTORY ${GEN_DIR} DESTINATION include + FILES_MATCHING PATTERN "*.pb.h" ) install( @@ -63,5 +126,6 @@ install( INCLUDES DESTINATION include ) -ament_export_targets(${PROJECT_NAME}) +ament_export_targets(${PROJECT_NAME} HAS_LIBRARY_TARGET) +ament_export_dependencies(Protobuf) ament_package() diff --git a/src/rj_protos/protos/ssl-game-controller b/src/rj_protos/protos/ssl-game-controller deleted file mode 160000 index b176f48c9aa..00000000000 --- a/src/rj_protos/protos/ssl-game-controller +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b176f48c9aa2c1dbfdf4ee7bb39548630a734b91 diff --git a/src/rj_protos/protos/ssl_simulation_config.proto b/src/rj_protos/protos/ssl_simulation_config.proto deleted file mode 100644 index 885d2af75c3..00000000000 --- a/src/rj_protos/protos/ssl_simulation_config.proto +++ /dev/null @@ -1,77 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -import "ssl_gc_common.proto"; -import "ssl_vision_geometry.proto"; -import "google/protobuf/any.proto"; - -// Movement limits for a robot -message RobotLimits { - // Max absolute speed-up acceleration [m/s^2] - optional float acc_speedup_absolute_max = 1; - // Max angular speed-up acceleration [rad/s^2] - optional float acc_speedup_angular_max = 2; - // Max absolute brake acceleration [m/s^2] - optional float acc_brake_absolute_max = 3; - // Max angular brake acceleration [rad/s^2] - optional float acc_brake_angular_max = 4; - // Max absolute velocity [m/s] - optional float vel_absolute_max = 5; - // Max angular velocity [rad/s] - optional float vel_angular_max = 6; -} - -// Robot wheel angle configuration -// all angles are relative to looking forward, -// all wheels / angles are clockwise -message RobotWheelAngles { - // Angle front right [rad] - required float front_right = 1; - // Angle back right [rad] - required float back_right = 2; - // Angle back left [rad] - required float back_left = 3; - // Angle front left [rad] - required float front_left = 4; -} - -// Specs of a robot -message RobotSpecs { - // Id of the robot - required RobotId id = 1; - // Robot radius [m] - optional float radius = 2 [default = 0.09]; - // Robot height [m] - optional float height = 3 [default = 0.15]; - // Robot mass [kg] - optional float mass = 4; - // Max linear kick speed [m/s] (unset = unlimited) - optional float max_linear_kick_speed = 7; - // Max chip kick speed [m/s] (unset = unlimited) - optional float max_chip_kick_speed = 8; - // Distance from robot center to dribbler [m] (implicitly defines the opening angle and dribbler width) - optional float center_to_dribbler = 9; - // Movement limits - optional RobotLimits limits = 10; - // Wheel angle configuration - optional RobotWheelAngles wheel_angles = 13; - // Custom robot spec for specific simulators (the protobuf files are managed by the simulators) - optional google.protobuf.Any custom = 14; -} - -message RealismConfig { - // Custom config for specific simulators (the protobuf files are managed by the simulators) - optional google.protobuf.Any custom = 1; -} - -// Change the simulator configuration -message SimulatorConfig { - // Update the geometry - optional SSL_GeometryData geometry = 1; - // Update the robot specs - repeated RobotSpecs robot_specs = 2; - // Update realism configuration - optional RealismConfig realism_config = 3; - // Change the vision publish port - optional uint32 vision_port = 4; -} \ No newline at end of file diff --git a/src/rj_protos/protos/ssl_simulation_control.proto b/src/rj_protos/protos/ssl_simulation_control.proto deleted file mode 100644 index a9b5c5919c9..00000000000 --- a/src/rj_protos/protos/ssl_simulation_control.proto +++ /dev/null @@ -1,73 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -import "ssl_gc_common.proto"; -import "ssl_simulation_config.proto"; -import "ssl_simulation_error.proto"; - -// Teleport the ball to a new location and optionally set it to some velocity -message TeleportBall { - // x-coordinate [m] - optional float x = 1; - // y-coordinate [m] - optional float y = 2; - // z-coordinate (height) [m] - optional float z = 3; - // Velocity in x-direction [m/s] - optional float vx = 4; - // Velocity in y-direction [m/s] - optional float vy = 5; - // Velocity in z-direction [m/s] - optional float vz = 6; - // Teleport the ball safely to the target, for example by - // moving robots out of the way in case of collision and set speed of robots close-by to zero - optional bool teleport_safely = 7 [default = false]; - // Adapt the angular ball velocity such that the ball is rolling - optional bool roll = 8 [default = false]; -} - -// Teleport a robot to some location and give it a velocity -message TeleportRobot { - // Robot id to teleport - required RobotId id = 1; - // x-coordinate [m] - optional float x = 2; - // y-coordinate [m] - optional float y = 3; - // Orientation [rad], measured from the x-axis counter-clockwise - optional float orientation = 4; - // Global velocity [m/s] towards x-axis - optional float v_x = 5 [default = 0]; - // Global velocity [m/s] towards y-axis - optional float v_y = 6 [default = 0]; - // Angular velocity [rad/s] - optional float v_angular = 7 [default = 0]; - // Robot should be present on the field? - // true -> robot will be added, if it does not exist yet - // false -> robot will be removed, if it is present - optional bool present = 8; -} - -// Control the simulation -message SimulatorControl { - // Teleport the ball - optional TeleportBall teleport_ball = 1; - // Teleport robots - repeated TeleportRobot teleport_robot = 2; - // Change the simulation speed - optional float simulation_speed = 3; -} - -// Command from the connected client to the simulator -message SimulatorCommand { - // Control the simulation - optional SimulatorControl control = 1; - // Configure the simulation - optional SimulatorConfig config = 2; -} - -// Response of the simulator to the connected client -message SimulatorResponse { - // List of errors, like using unsupported features - repeated SimulatorError errors = 1; -} diff --git a/src/rj_protos/protos/ssl_simulation_error.proto b/src/rj_protos/protos/ssl_simulation_error.proto deleted file mode 100644 index 92c732fa254..00000000000 --- a/src/rj_protos/protos/ssl_simulation_error.proto +++ /dev/null @@ -1,10 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -// Errors in the simulator -message SimulatorError { - // Unique code of the error for automatic handling on client side - optional string code = 1; - // Human readable description of the error - optional string message = 2; -} diff --git a/src/rj_protos/protos/ssl_simulation_robot_control.proto b/src/rj_protos/protos/ssl_simulation_robot_control.proto deleted file mode 100644 index 981b8436826..00000000000 --- a/src/rj_protos/protos/ssl_simulation_robot_control.proto +++ /dev/null @@ -1,66 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -// Full command for a single robot -message RobotCommand { - // Id of the robot - required uint32 id = 1; - // Movement command - optional RobotMoveCommand move_command = 2; - // Absolute (3 dimensional) kick speed [m/s] - optional float kick_speed = 3; - // Kick angle [degree] (defaults to 0 degrees for a straight kick) - optional float kick_angle = 4 [default = 0]; - // Dribbler speed in rounds per minute [rpm] - optional float dribbler_speed = 5; -} - -// Wrapper for different kinds of movement commands -message RobotMoveCommand { - oneof command { - // Move with wheel velocities - MoveWheelVelocity wheel_velocity = 1; - // Move with local velocity - MoveLocalVelocity local_velocity = 2; - // Move with global velocity - MoveGlobalVelocity global_velocity = 3; - } -} - -// Move robot with wheel velocities -message MoveWheelVelocity { - // Velocity [m/s] of front right wheel - required float front_right = 1; - // Velocity [m/s] of back right wheel - required float back_right = 2; - // Velocity [m/s] of back left wheel - required float back_left = 3; - // Velocity [m/s] of front left wheel - required float front_left = 4; -} - -// Move robot with local velocity -message MoveLocalVelocity { - // Velocity forward [m/s] (towards the dribbler) - required float forward = 1; - // Velocity to the left [m/s] - required float left = 2; - // Angular velocity counter-clockwise [rad/s] - required float angular = 3; -} - -// Move robot with global velocity -message MoveGlobalVelocity { - // Velocity on x-axis of the field [m/s] - required float x = 1; - // Velocity on y-axis of the field [m/s] - required float y = 2; - // Angular velocity counter-clockwise [rad/s] - required float angular = 3; -} - -// Command from the connected client to the simulator -message RobotControl { - // Control the robots - repeated RobotCommand robot_commands = 1; -} diff --git a/src/rj_protos/protos/ssl_simulation_robot_feedback.proto b/src/rj_protos/protos/ssl_simulation_robot_feedback.proto deleted file mode 100644 index ddbf214f61f..00000000000 --- a/src/rj_protos/protos/ssl_simulation_robot_feedback.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -import "ssl_simulation_error.proto"; -import "google/protobuf/any.proto"; - -// Feedback from a robot -message RobotFeedback { - // Id of the robot - required uint32 id = 1; - // Has the dribbler contact to the ball right now - optional bool dribbler_ball_contact = 2; - // Custom robot feedback for specific simulators (the protobuf files are managed by the simulators) - optional google.protobuf.Any custom = 3; -} - -// Response to RobotControl from the simulator to the connected client -message RobotControlResponse { - // List of errors, like using unsupported features - repeated SimulatorError errors = 1; - // Feedback of the robots - repeated RobotFeedback feedback = 2; -} diff --git a/src/rj_protos/protos/ssl_simulation_synchronous.proto b/src/rj_protos/protos/ssl_simulation_synchronous.proto deleted file mode 100644 index b8dde5dd4b1..00000000000 --- a/src/rj_protos/protos/ssl_simulation_synchronous.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -import "ssl_vision_detection.proto"; -import "ssl_simulation_robot_feedback.proto"; -import "ssl_simulation_robot_control.proto"; -import "ssl_simulation_control.proto"; - -// Request from the team to the simulator -message SimulationSyncRequest { - // The simulation step [s] to perform - optional float sim_step = 1; - // An optional simulator command - optional SimulatorCommand simulator_command = 2; - // An optional robot control command - optional RobotControl robot_control = 3; -} - -// Response to last SimulationSyncRequest -message SimulationSyncResponse { - // List of detection frames for all cameras with the state after the simulation step in the request was performed - repeated SSL_DetectionFrame detection = 1; - // An optional robot control response - optional RobotControlResponse robot_control_response = 2; -} diff --git a/src/rj_protos/protos/ssl_vision_detection.proto b/src/rj_protos/protos/ssl_vision_detection.proto deleted file mode 100644 index 0586974f111..00000000000 --- a/src/rj_protos/protos/ssl_vision_detection.proto +++ /dev/null @@ -1,33 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -message SSL_DetectionBall { - required float confidence = 1; - optional uint32 area = 2; - required float x = 3; - required float y = 4; - optional float z = 5; - required float pixel_x = 6; - required float pixel_y = 7; -} - -message SSL_DetectionRobot { - required float confidence = 1; - optional uint32 robot_id = 2; - required float x = 3; - required float y = 4; - optional float orientation = 5; - required float pixel_x = 6; - required float pixel_y = 7; - optional float height = 8; -} - -message SSL_DetectionFrame { - required uint32 frame_number = 1; - required double t_capture = 2; - required double t_sent = 3; - required uint32 camera_id = 4; - repeated SSL_DetectionBall balls = 5; - repeated SSL_DetectionRobot robots_yellow = 6; - repeated SSL_DetectionRobot robots_blue = 7; -} diff --git a/src/rj_protos/protos/ssl_vision_geometry.proto b/src/rj_protos/protos/ssl_vision_geometry.proto deleted file mode 100644 index 440fd1e10a6..00000000000 --- a/src/rj_protos/protos/ssl_vision_geometry.proto +++ /dev/null @@ -1,130 +0,0 @@ -syntax = "proto2"; -option go_package = "github.com/RoboCup-SSL/ssl-simulation-protocol/pkg/sim"; - -// A 2D float vector. -message Vector2f { - required float x = 1; - required float y = 2; -} - -// Represents a field marking as a line segment represented by a start point p1, -// and end point p2, and a line thickness. The start and end points are along -// the center of the line, so the thickness of the line extends by thickness / 2 -// on either side of the line. -message SSL_FieldLineSegment { - // Name of this field marking. - required string name = 1; - // Start point of the line segment. - required Vector2f p1 = 2; - // End point of the line segment. - required Vector2f p2 = 3; - // Thickness of the line segment. - required float thickness = 4; - // The type of this shape - optional SSL_FieldShapeType type = 5; -} - -// Represents a field marking as a circular arc segment represented by center point, a -// start angle, an end angle, and an arc thickness. -message SSL_FieldCircularArc { - // Name of this field marking. - required string name = 1; - // Center point of the circular arc. - required Vector2f center = 2; - // Radius of the arc. - required float radius = 3; - // Start angle in counter-clockwise order. - required float a1 = 4; - // End angle in counter-clockwise order. - required float a2 = 5; - // Thickness of the arc. - required float thickness = 6; - // The type of this shape - optional SSL_FieldShapeType type = 7; -} - -message SSL_GeometryFieldSize { - required int32 field_length = 1; - required int32 field_width = 2; - required int32 goal_width = 3; - required int32 goal_depth = 4; - required int32 boundary_width = 5; - repeated SSL_FieldLineSegment field_lines = 6; - repeated SSL_FieldCircularArc field_arcs = 7; - optional int32 penalty_area_depth = 8; - optional int32 penalty_area_width = 9; -} - -message SSL_GeometryCameraCalibration { - required uint32 camera_id = 1; - required float focal_length = 2; - required float principal_point_x = 3; - required float principal_point_y = 4; - required float distortion = 5; - required float q0 = 6; - required float q1 = 7; - required float q2 = 8; - required float q3 = 9; - required float tx = 10; - required float ty = 11; - required float tz = 12; - optional float derived_camera_world_tx = 13; - optional float derived_camera_world_ty = 14; - optional float derived_camera_world_tz = 15; - optional uint32 pixel_image_width = 16; - optional uint32 pixel_image_height = 17; -} - -// Two-Phase model for straight-kicked balls. -// There are two phases with different accelerations during the ball kicks: -// 1. Sliding -// 2. Rolling -// The full model is described in the TDP of ER-Force from 2016, which can be found here: -// https://ssl.robocup.org/wp-content/uploads/2019/01/2016_ETDP_ER-Force.pdf -message SSL_BallModelStraightTwoPhase { - // Ball sliding acceleration [m/s^2] (should be negative) - required double acc_slide = 1; - // Ball rolling acceleration [m/s^2] (should be negative) - required double acc_roll = 2; - // Fraction of the initial velocity where the ball starts to roll - required double k_switch = 3; -} - -// Fixed-Loss model for chipped balls. -// Uses fixed damping factors for xy and z direction per hop. -message SSL_BallModelChipFixedLoss { - // Chip kick velocity damping factor in XY direction for the first hop - required double damping_xy_first_hop = 1; - // Chip kick velocity damping factor in XY direction for all following hops - required double damping_xy_other_hops = 2; - // Chip kick velocity damping factor in Z direction for all hops - required double damping_z = 3; -} - -message SSL_GeometryModels { - optional SSL_BallModelStraightTwoPhase straight_two_phase = 1; - optional SSL_BallModelChipFixedLoss chip_fixed_loss = 2; -} - -message SSL_GeometryData { - required SSL_GeometryFieldSize field = 1; - repeated SSL_GeometryCameraCalibration calib = 2; - optional SSL_GeometryModels models = 3; -} - -enum SSL_FieldShapeType { - Undefined = 0; - CenterCircle = 1; - TopTouchLine = 2; - BottomTouchLine = 3; - LeftGoalLine = 4; - RightGoalLine = 5; - HalfwayLine = 6; - CenterLine = 7; - LeftPenaltyStretch = 8; - RightPenaltyStretch = 9; - LeftFieldLeftPenaltyStretch = 10; - LeftFieldRightPenaltyStretch = 11; - RightFieldLeftPenaltyStretch = 12; - RightFieldRightPenaltyStretch = 13; -} \ No newline at end of file diff --git a/src/rj_protos/protos/ssl_vision_wrapper.proto b/src/rj_protos/protos/ssl_vision_wrapper.proto deleted file mode 100644 index e8be7fb0aa8..00000000000 --- a/src/rj_protos/protos/ssl_vision_wrapper.proto +++ /dev/null @@ -1,9 +0,0 @@ -syntax = "proto2"; - -import "ssl_vision_detection.proto"; -import "ssl_vision_geometry.proto"; - -message SSL_WrapperPacket { - optional SSL_DetectionFrame detection = 1; - optional SSL_GeometryData geometry = 2; -} diff --git a/src/rj_protos/ssl-simulation-protocol b/src/rj_protos/ssl-simulation-protocol new file mode 160000 index 00000000000..65ad6148671 --- /dev/null +++ b/src/rj_protos/ssl-simulation-protocol @@ -0,0 +1 @@ +Subproject commit 65ad6148671a2b1ead58be0b625ca0f8d269ced8 diff --git a/src/rj_radio/src/sim_radio.cpp b/src/rj_radio/src/sim_radio.cpp index 11e36b360ee..acd6c29bc2e 100644 --- a/src/rj_radio/src/sim_radio.cpp +++ b/src/rj_radio/src/sim_radio.cpp @@ -42,7 +42,7 @@ static SimulatorCommand convert_placement_to_proto( // TODO(Kevin): make this only happen in sim (set a param) // this line sets robots with an ID above 6 to "not present", meaning // they will be removed on their next sim command - // see "rj_protos/proto/ssl_simulation_control.proto" + // see "rj_protos/ssl-simulation-protocol/proto/ssl_simulation_control.proto" // // to see this in effect, click and drag the robots expected to be not // present and they should disappear diff --git a/src/rj_referee/include/rj_referee/external_referee.hpp b/src/rj_referee/include/rj_referee/external_referee.hpp index 6c1821b242e..44a7eacc918 100644 --- a/src/rj_referee/include/rj_referee/external_referee.hpp +++ b/src/rj_referee/include/rj_referee/external_referee.hpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/rj_ui/include/rj_ui/main_window.hpp b/src/rj_ui/include/rj_ui/main_window.hpp index 87dafc5c461..6218b75c065 100644 --- a/src/rj_ui/include/rj_ui/main_window.hpp +++ b/src/rj_ui/include/rj_ui/main_window.hpp @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include diff --git a/src/rj_ui/include/rj_ui/sim_field_view.hpp b/src/rj_ui/include/rj_ui/sim_field_view.hpp index d4dbf720e71..73b2a290617 100644 --- a/src/rj_ui/include/rj_ui/sim_field_view.hpp +++ b/src/rj_ui/include/rj_ui/sim_field_view.hpp @@ -13,9 +13,6 @@ #include #include #include -#include -#include -#include #include "rj_ui/field_view.hpp" diff --git a/src/rj_ui/src/main_window.cpp b/src/rj_ui/src/main_window.cpp index aa9fd6b2663..075e3a4af84 100644 --- a/src/rj_ui/src/main_window.cpp +++ b/src/rj_ui/src/main_window.cpp @@ -34,8 +34,6 @@ #include #include #include -#include -#include #include #include diff --git a/src/rj_ui/src/sim_field_view.cpp b/src/rj_ui/src/sim_field_view.cpp index 7defc35567a..a56091b9ebe 100644 --- a/src/rj_ui/src/sim_field_view.cpp +++ b/src/rj_ui/src/sim_field_view.cpp @@ -10,9 +10,6 @@ #include #include #include -#include -#include -#include #include "rj_ui/field_view.hpp" diff --git a/src/rj_utils/include/rj_utils/conversions.hpp b/src/rj_utils/include/rj_utils/conversions.hpp index f8d868c7873..32d95f85b3b 100644 --- a/src/rj_utils/include/rj_utils/conversions.hpp +++ b/src/rj_utils/include/rj_utils/conversions.hpp @@ -1,7 +1,6 @@ #pragma once -#include -#include +#include #include #include #include diff --git a/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp b/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp index 83092aa6441..07c37b7e1a7 100644 --- a/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp +++ b/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/src/rj_vision_receiver/include/rj_vision_receiver/vision_receiver.hpp b/src/rj_vision_receiver/include/rj_vision_receiver/vision_receiver.hpp index 1380db4ac19..94af2c30f49 100644 --- a/src/rj_vision_receiver/include/rj_vision_receiver/vision_receiver.hpp +++ b/src/rj_vision_receiver/include/rj_vision_receiver/vision_receiver.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include From 2e850b50feedac17cfeb721aff8b5018a4da5a43 Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 20:45:08 -0400 Subject: [PATCH 14/21] . --- src/rj_geometry/CMakeLists.txt | 2 -- src/rj_geometry/package.xml | 1 - src/rj_protos/CMakeLists.txt | 10 +++------- src/rj_protos/README.md | 30 +++++++++++++++--------------- src/rj_ui/CMakeLists.txt | 2 -- src/rj_ui/package.xml | 1 - 6 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/rj_geometry/CMakeLists.txt b/src/rj_geometry/CMakeLists.txt index 8eafc55f32e..e6b3441f99d 100644 --- a/src/rj_geometry/CMakeLists.txt +++ b/src/rj_geometry/CMakeLists.txt @@ -14,7 +14,6 @@ find_package(Eigen3 REQUIRED) find_package(eigen3_cmake_module REQUIRED) find_package(Qt5 COMPONENTS Core REQUIRED) find_package(fmt REQUIRED) -find_package(rj_protos REQUIRED) find_package(rj_convert REQUIRED) find_package(rosidl_default_generators REQUIRED) find_package(std_msgs REQUIRED) @@ -23,7 +22,6 @@ find_package(rj_geometry_msgs REQUIRED) set(RJ_GEOMETRY_DEPS Eigen3 fmt - rj_protos rj_convert rj_geometry_msgs ) diff --git a/src/rj_geometry/package.xml b/src/rj_geometry/package.xml index 0f10d9212e2..1573163a2aa 100644 --- a/src/rj_geometry/package.xml +++ b/src/rj_geometry/package.xml @@ -13,7 +13,6 @@ eigen3 std_msgs - rj_protos rj_convert rj_geometry_msgs diff --git a/src/rj_protos/CMakeLists.txt b/src/rj_protos/CMakeLists.txt index 094a75a9ef4..082b243ecda 100644 --- a/src/rj_protos/CMakeLists.txt +++ b/src/rj_protos/CMakeLists.txt @@ -33,11 +33,9 @@ set(SIM_PROTOS ssl_simulation_synchronous.proto ) -# ssl-simulation-protocol vendors its own flat copies of ssl_gc_common and -# ssl_vision_{detection,geometry}. Protobuf identifies files by import path, so -# compiling both copies would define RobotId etc. twice. Stage the sim protos -# with those imports pointed at the ssl-game-controller files instead; the -# submodule itself is left untouched. +# There are duplicate protos in ssl-game-controller and ssl-simulation-protocol. +# In order to avoid duplicates, we rename the imports in ssl-simulation-protocol +# to point to the ssl-game-controller ones instead. set(SIM_IMPORT_REWRITES "ssl_gc_common.proto" "state/ssl_gc_common.proto" "ssl_vision_detection.proto" "vision/ssl_vision_detection.proto" @@ -99,8 +97,6 @@ target_link_libraries(${PROJECT_NAME} protobuf::libprotobuf ) -# Consumers include ; generated code includes e.g. -# "state/ssl_gc_common.pb.h", so the rj_protos dir itself is also needed. target_include_directories(${PROJECT_NAME} PUBLIC $ diff --git a/src/rj_protos/README.md b/src/rj_protos/README.md index 12b1b9e3530..ddfde5d5f02 100644 --- a/src/rj_protos/README.md +++ b/src/rj_protos/README.md @@ -4,10 +4,10 @@ Reusable assessment, refactor, and verification template. | Package Details | Entry | | --- | --- | -| **Package name** | | -| **Assigned owner(s)** | | -| **Reviewer(s)** | | -| **Date started revision** | | +| **Package name** | `rj_protos` | +| **Assigned owner(s)** | Sanat Dhanyamraju | +| **Reviewer(s)** | Cameron Lyon, Nate Wert | +| **Date started revision** | 9/1/2026 | ## 1. Package Identity and Tier @@ -15,9 +15,9 @@ Define the package's purpose and fixed architectural classification before work | Field | Details | | --- | --- | -| **Plain-language purpose** | _Explain what the package does so a new contributor can understand it._ | -| **Current responsibilities** | _List the responsibilities currently owned by this package._ | -| **Out of scope** | _State what this package must not own or attempt to solve._ | +| **Plain-language purpose** | Contains protobuf files for SSL-owned interfaces such as game controller and vision processor. | +| **Current responsibilities** | Owns the protocol for recieving data from SSL-owned interfaces. | +| **Out of scope** | Does not contain any logic behind how these messages are parsed or how the data is used. | ## 2. Dependency Rules @@ -27,17 +27,17 @@ Map package relationships before adding, deleting, or moving code. Dependency di | Field | Details | | --- | --- | -| **Depends on** | _Enter the explicit dependency list from `package.xml`._ | -| **Depended on by** | _List packages, executables, or systems that consume this package._ | +| **Depends on** | None | +| **Depended on by** | `rj_common`, `rj_radio`, `rj_referee`, `rj_utils`, `rj_vision_receiver` | ## 3. Operational Expectations | Field | Details | | --- | --- | -| **Failure behavior** | _Describe behavior when an upstream input, sensor, network link, radio, or other dependency fails._ | -| **Recovery behavior** | _Describe automatic recovery, retry, fallback, and operator intervention requirements._ | -| **Configuration** | _List required parameters, defaults, validation rules, and configuration files._ | +| **Failure behavior** | If the SSL protos migrate to a different repo, this will no longer stay up-to-date with SSL. | +| **Recovery behavior** | Modify the package to submodule the new repo. | +| **Configuration** | CMakeLists.txt contains the list of protos we build, this needs to be updated when we want to use a new proto from SSL. | ## 4. Testing @@ -45,6 +45,6 @@ Map package relationships before adding, deleting, or moving code. Dependency di | Field | Details | | --- | --- | -| **Unit testing** | _Describe what unit tests were used on this package and how._ | -| **Coverage gaps** | _List untested algorithms, branches, failure paths, and outlier cases._ | -| **Observed outliers** | _Record flaky behavior, nondeterminism, timing spikes, or unexpected results._ | +| **Unit testing** | No testing exists as this package contains no code. | +| **Coverage gaps** | N/A | +| **Observed outliers** | N/A | diff --git a/src/rj_ui/CMakeLists.txt b/src/rj_ui/CMakeLists.txt index fb5525eefcf..ebedc0c09d8 100644 --- a/src/rj_ui/CMakeLists.txt +++ b/src/rj_ui/CMakeLists.txt @@ -22,7 +22,6 @@ find_package(std_msgs REQUIRED) find_package(fmt REQUIRED) find_package(rj_common REQUIRED) find_package(rj_param_utils REQUIRED) -find_package(rj_protos REQUIRED) find_package(rj_geometry REQUIRED) find_package(rj_utils REQUIRED) find_package(rj_planning REQUIRED) @@ -92,7 +91,6 @@ set(RJ_UI_DEPS fmt rj_common rj_param_utils - rj_protos rj_geometry rj_utils rj_planning diff --git a/src/rj_ui/package.xml b/src/rj_ui/package.xml index e9e812c736a..7384e85eab0 100644 --- a/src/rj_ui/package.xml +++ b/src/rj_ui/package.xml @@ -18,7 +18,6 @@ rj_common rj_param_utils - rj_protos rj_geometry rj_utils rj_planning From 23ebb31546ee8b6b5b91008c0b6316a21647408a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 20:55:45 -0400 Subject: [PATCH 15/21] Fix Code Style On sd/rj_protos (#2583) automated style fixes Co-authored-by: sanatd33 --- src/rj_common/include/rj_common/referee_enums.hpp | 4 ++-- src/rj_common/include/rj_common/team_info.hpp | 6 +++--- src/rj_utils/include/rj_utils/conversions.hpp | 2 +- .../include/rj_vision_receiver/stamped_wrapper_packet.hpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/rj_common/include/rj_common/referee_enums.hpp b/src/rj_common/include/rj_common/referee_enums.hpp index 08682c8d78d..ef19445e57c 100644 --- a/src/rj_common/include/rj_common/referee_enums.hpp +++ b/src/rj_common/include/rj_common/referee_enums.hpp @@ -1,9 +1,9 @@ #pragma once -#include - #include +#include + namespace referee_module_enums { using Stage = Referee_Stage; diff --git a/src/rj_common/include/rj_common/team_info.hpp b/src/rj_common/include/rj_common/team_info.hpp index 542d087413c..4aabff6622d 100644 --- a/src/rj_common/include/rj_common/team_info.hpp +++ b/src/rj_common/include/rj_common/team_info.hpp @@ -1,11 +1,11 @@ #pragma once -#include +#include +#include #include #include -#include -#include +#include // Information about a single team. class TeamInfo { diff --git a/src/rj_utils/include/rj_utils/conversions.hpp b/src/rj_utils/include/rj_utils/conversions.hpp index 32d95f85b3b..53960837694 100644 --- a/src/rj_utils/include/rj_utils/conversions.hpp +++ b/src/rj_utils/include/rj_utils/conversions.hpp @@ -1,10 +1,10 @@ #pragma once -#include #include #include #include #include +#include using RawProtobufMsg = rj_msgs::msg::RawProtobuf; using DetectionBallMsg = rj_msgs::msg::DetectionBall; diff --git a/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp b/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp index 07c37b7e1a7..4a0d6405505 100644 --- a/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp +++ b/src/rj_vision_receiver/include/rj_vision_receiver/stamped_wrapper_packet.hpp @@ -1,9 +1,9 @@ #pragma once -#include - #include +#include + namespace vision_receiver { /** * @brief A struct that adds receive time information to a SSL_WrapperPacket. From 3a2092749df3c9e345457f94b47fc302924c5542 Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 21:07:01 -0400 Subject: [PATCH 16/21] add submodules to build --- makefile | 3 +++ util/ubuntu-setup | 3 +++ 2 files changed, 6 insertions(+) diff --git a/makefile b/makefile index 56ad6905c67..ed509c0ff53 100644 --- a/makefile +++ b/makefile @@ -236,3 +236,6 @@ checktidy-lines: @echo "Removing GCC precompiled headers from compile_commands.json so that clang-tidy will work" @sed -i 's/-include [^ ]*cmake_pch\.hxx//' $(COMPILE_COMMANDS_DIR)/compile_commands.json @git diff -U0 --no-color $(DIFFBASE) | python3 util/clang-tidy-diff.py -clang-tidy-binary $(CLANG_TIDY_BINARY) -p1 -path $(COMPILE_COMMANDS_DIR) -j$(CORES) -checks=-google-runtime-references + +update-submodules: + git submodule update --init --recursive diff --git a/util/ubuntu-setup b/util/ubuntu-setup index efa399dd9d7..4f8e4fa459f 100755 --- a/util/ubuntu-setup +++ b/util/ubuntu-setup @@ -166,3 +166,6 @@ apt-get install $ARGS $PACKAGES # install python3 requirements python3 -m pip install pip==22.1 pip3 install -r $BASE/util/requirements3.txt + +# update submodules +make update-submodules From 0519b01ce9aa26f71db374ada81ae06d1e5876cd Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 21:24:30 -0400 Subject: [PATCH 17/21] / --- .github/workflows/ci.yml | 3 +++ util/ubuntu-setup | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6500958b70a..a9d06bfc74f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,9 @@ jobs: with: fetch-depth: 0 + - name: Update Submodules + run: make update-submodules + - name: Run util/ubuntu-setup as sudo run: "./util/ubuntu-setup -y" diff --git a/util/ubuntu-setup b/util/ubuntu-setup index 4f8e4fa459f..5b6b5262735 100755 --- a/util/ubuntu-setup +++ b/util/ubuntu-setup @@ -168,4 +168,6 @@ python3 -m pip install pip==22.1 pip3 install -r $BASE/util/requirements3.txt # update submodules -make update-submodules +if ! $NO_SUBMODULES; then + make update-submodules +fi From 055e184b755a5d347df99faad37edbd4586a4f24 Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 21:25:08 -0400 Subject: [PATCH 18/21] . --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9d06bfc74f..9904d680de9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: run: make update-submodules - name: Run util/ubuntu-setup as sudo - run: "./util/ubuntu-setup -y" + run: "./util/ubuntu-setup -y --no-submodules" - name: Build run: source /opt/ros/humble/setup.bash && colcon build --parallel-workers 4 From d2c3d8bf6f055ff1cf7d65e5e6756b005a7afec7 Mon Sep 17 00:00:00 2001 From: rishiso Date: Tue, 29 Sep 2026 21:28:25 -0400 Subject: [PATCH 19/21] . --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9904d680de9..49859edf61b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,9 +16,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 - - - name: Update Submodules - run: make update-submodules + submodules: recursive - name: Run util/ubuntu-setup as sudo run: "./util/ubuntu-setup -y --no-submodules" From 774b8e909de0f4bb1c2584105278f79c4eed0512 Mon Sep 17 00:00:00 2001 From: Sanat Dhanyamraju Date: Sun, 11 Oct 2026 17:03:38 -0400 Subject: [PATCH 20/21] comments --- src/rj_protos/CMakeLists.txt | 6 ++++++ src/rj_protos/README.md | 2 +- util/ubuntu-setup | 10 +++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/rj_protos/CMakeLists.txt b/src/rj_protos/CMakeLists.txt index 082b243ecda..ae1be815049 100644 --- a/src/rj_protos/CMakeLists.txt +++ b/src/rj_protos/CMakeLists.txt @@ -42,6 +42,12 @@ set(SIM_IMPORT_REWRITES "ssl_vision_geometry.proto" "vision/ssl_vision_geometry.proto" ) +if(NOT EXISTS ${SIM_PROTO_ROOT} OR NOT EXISTS ${GC_PROTO_ROOT}) + message(FATAL_ERROR + "Proto submodule is missing. " + "From the repo root, run: make update-submodules") +endif() + foreach(proto ${SIM_PROTOS}) file(READ ${SIM_PROTO_SRC}/${proto} content) set(rewrites ${SIM_IMPORT_REWRITES}) diff --git a/src/rj_protos/README.md b/src/rj_protos/README.md index ddfde5d5f02..4f1fc510b98 100644 --- a/src/rj_protos/README.md +++ b/src/rj_protos/README.md @@ -16,7 +16,7 @@ Define the package's purpose and fixed architectural classification before work | Field | Details | | --- | --- | | **Plain-language purpose** | Contains protobuf files for SSL-owned interfaces such as game controller and vision processor. | -| **Current responsibilities** | Owns the protocol for recieving data from SSL-owned interfaces. | +| **Current responsibilities** | Owns the protocol for receiving data from SSL-owned interfaces. | | **Out of scope** | Does not contain any logic behind how these messages are parsed or how the data is used. | ## 2. Dependency Rules diff --git a/util/ubuntu-setup b/util/ubuntu-setup index 5b6b5262735..6da95c265f1 100755 --- a/util/ubuntu-setup +++ b/util/ubuntu-setup @@ -167,7 +167,11 @@ apt-get install $ARGS $PACKAGES python3 -m pip install pip==22.1 pip3 install -r $BASE/util/requirements3.txt -# update submodules +# update submodules as original user if ! $NO_SUBMODULES; then - make update-submodules -fi + if [ -n "${SUDO_USER:-}" ]; then + sudo -u "$SUDO_USER" -- make -C "$BASE" update-submodules + else + make -C "$BASE" update-submodules + fi +fi \ No newline at end of file From 5308013ef8be7db8f476758b307e595c4c083d66 Mon Sep 17 00:00:00 2001 From: Sanat Dhanyamraju Date: Sun, 11 Oct 2026 17:08:55 -0400 Subject: [PATCH 21/21] i had the wrong directory --- src/rj_protos/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rj_protos/CMakeLists.txt b/src/rj_protos/CMakeLists.txt index ae1be815049..dc5b624502d 100644 --- a/src/rj_protos/CMakeLists.txt +++ b/src/rj_protos/CMakeLists.txt @@ -42,7 +42,7 @@ set(SIM_IMPORT_REWRITES "ssl_vision_geometry.proto" "vision/ssl_vision_geometry.proto" ) -if(NOT EXISTS ${SIM_PROTO_ROOT} OR NOT EXISTS ${GC_PROTO_ROOT}) +if(NOT EXISTS ${SIM_PROTO_SRC} OR NOT EXISTS ${GC_PROTO_ROOT}) message(FATAL_ERROR "Proto submodule is missing. " "From the repo root, run: make update-submodules")