Skip to content

feat: add eagleye_result_logger for CSV regression logging#367

Open
rsasaki0109 wants to merge 6 commits intomain-ros2from
feature/result-logger
Open

feat: add eagleye_result_logger for CSV regression logging#367
rsasaki0109 wants to merge 6 commits intomain-ros2from
feature/result-logger

Conversation

@rsasaki0109
Copy link
Copy Markdown
Collaborator

Summary

  • /eagleye/fix (NavSatFix) と /eagleye/eagleye/pose (PoseStamped) をタイムスタンプ付き CSV に保存する新パッケージ eagleye_result_logger を追加
  • リファクタリング前後の推定結果比較(リグレッションテスト)に使用

出力ファイル

ファイル トピック カラム
fix_YYYYMMDD_HHMMSS.csv /eagleye/fix timestamp_s, latitude, longitude, altitude, status
pose_YYYYMMDD_HHMMSS.csv /eagleye/eagleye/pose timestamp_s, x, y, z, qx, qy, qz, qw

使い方

# eagleye と同時に起動
ros2 launch eagleye_result_logger result_logger.launch.xml output_dir:=/tmp/results

# トピック名変更も可能
ros2 launch eagleye_result_logger result_logger.launch.xml \
  output_dir:=/tmp/results \
  fix_topic:=/eagleye/fix \
  pose_topic:=/eagleye/eagleye/pose

Add devcontainer for ROS2 Humble development
…attern

Replace global static variables and free callback functions with
encapsulated class-based rclcpp::Node pattern across all 21 nodes.
Also fix CMakeLists.txt ROS_DISTRO comparison (quoted env var).

- Each node is now a class inheriting rclcpp::Node
- Subscribers, publishers, and timers are private member variables
- Callbacks are private member functions
- GenericTimer replaced with create_wall_timer()
- Nodes with argc/argv routing (heading, rtk_heading, heading_interpolate,
  yaw_rate_offset) pass args through constructor
Global static variables are zero-initialized by C++ before program startup,
but class members with POD types (int, double, bool) are left uninitialized
when default-initialized. After the refactoring from global statics to class
members, all *Status structs had uninitialized fields, causing garbage values
in estimated outputs (e.g. yaw_rate_offset appearing as ~5.6e+79 rad/s).

Add = {} to each status struct member declaration to value-initialize them,
which zero-initializes all POD members and matches the original behavior.
…sion logging

Saves /eagleye/fix (NavSatFix) and /eagleye/eagleye/pose (PoseStamped)
to timestamped CSV files for before/after comparison.

Usage:
  ros2 launch eagleye_result_logger result_logger.launch.xml output_dir:=/tmp/results
Copy link
Copy Markdown

@windsurf-bot windsurf-bot bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other comments (20)
  • eagleye_rt/src/heading_node.cpp (31-31) Missing YAML include. The code uses YAML::LoadFile but doesn't include the yaml-cpp header.
  • eagleye_rt/src/slip_angle_node.cpp (128-132) The code is missing a subscription to the `velocity_status` topic, but `velocity_status_` is used in the `imuCallback` method when `use_can_less_mode_` is true. This could lead to undefined behavior since `velocity_status_` would never be updated.
  • eagleye_rt/src/velocity_scale_factor_node.cpp (287-287) The csv_file is created but there's no check if the file was successfully opened before writing to it. This could lead to silent failures when trying to save data.
        std::ofstream csv_file(velocity_scale_factor_save_str_);
        if (!csv_file) {
          RCLCPP_ERROR(this->get_logger(), "Failed to open file for writing: %s", velocity_scale_factor_save_str_.c_str());
          return;
        }
    
  • eagleye_rt/src/rolling_node.cpp (92-92) Consider initializing all member variables properly. While `rolling_status_` is initialized with empty braces, other message objects like `rolling_` are not explicitly initialized, which could lead to undefined behavior if any fields are accessed before being set.
  • eagleye_rt/src/yaw_rate_offset_node.cpp (171-171) The `use_can_less_mode_` member variable is initialized to false but never set to true anywhere in the code. If this mode is supposed to be configurable, consider adding a parameter to set it.
  • eagleye_rt/src/rtk_dead_reckoning_node.cpp (134-134) The `rtk_dead_reckoning_status_` is initialized with an empty initializer list `= {}`. Consider explicitly initializing all fields or using a constructor to ensure all status fields are properly initialized.
  • eagleye_rt/src/rtk_dead_reckoning_node.cpp (177-179) Consider adding error logging in the catch block for TransformException to help with debugging. The original code had a commented RCLCPP_ERROR line that could be restored.
  • eagleye_rt/src/yaw_rate_offset_stop_node.cpp (88-88) The `yaw_rate_offset_stop_status_` is initialized with empty braces, but it's not clear if all fields will be properly initialized this way. Consider explicitly initializing any fields that need specific initial values.
  • eagleye_rt/src/heading_interpolate_node.cpp (131-131) The heading_interpolate_status_ member is initialized with empty braces, but this might not properly initialize all fields. Consider explicitly initializing it in the constructor instead to ensure all fields are properly set.
  • eagleye_rt/src/heading_node.cpp (189-189) Consider initializing HeadingStatus with proper default values instead of empty braces, as some members might need specific initial values.
  • eagleye_rt/src/yaw_rate_offset_stop_node.cpp (63-64) There's a mismatch between the log message and the variable name. The log message says 'estimated_minimum_interval' but the variable is named 'estimated_interval'.
  • eagleye_rt/src/angular_velocity_offset_stop_node.cpp (82-83) The `angular_velocity_offset_stop_status_` struct is initialized with empty braces, but `angular_velocity_offset_stop_parameter_` is not initialized. Consider initializing it as well to avoid potential undefined behavior.
  • eagleye_rt/src/yaw_rate_offset_node.cpp (87-87) The error message formatting in the YAML exception catch block is incorrect. The ANSI color code is incomplete - it's missing the color number after the semicolon.
              std::cerr << "\033[1;31myaw_rate_offset_1st Node YAML Error: " << e.msg << "\033[0m"
    
  • eagleye_rt/src/yaw_rate_offset_node.cpp (129-129) The error message formatting in the second YAML exception catch block is also incorrect.
              std::cerr << "\033[1;31myaw_rate_offset_2nd Node YAML Error: " << e.msg << "\033[0m"
    
  • eagleye_util/result_logger/eagleye_result_logger/result_logger_node.py (38-38) The `sys` module is imported but not used in the code. Consider removing this unused import.
  • eagleye_util/result_logger/eagleye_result_logger/result_logger_node.py (31-33) The docstring mentions output files as `fix.csv` and `pose.csv`, but the actual implementation uses timestamped filenames like `fix_YYYYMMDD_HHMMSS.csv`. Please update the docstring to match the actual implementation.
  • eagleye_rt/src/height_node.cpp (129-129) Consider explicitly initializing all fields in the HeightStatus struct rather than using empty braces initialization. This ensures all fields have defined values.
  • eagleye_rt/src/velocity_estimator_node.cpp (82-82) For consistency with the other callback methods, consider using the same multi-line format for this method.
      void ggaCallback(const nmea_msgs::msg::Gpgga::ConstSharedPtr msg)
      {
        gga_msg_ = *msg;
      }
    
  • eagleye_rt/src/correction_imu.cpp (103-103) The condition check for acc_x_scale_factor_.status.enabled_status is missing the explicit `== true` comparison that is used for acc_x_offset_.status.enabled_status. For consistency and to avoid potential issues with non-boolean values, consider adding the explicit comparison.
        if (acc_x_offset_.status.enabled_status == true && acc_x_scale_factor_.status.enabled_status == true)
    
  • eagleye_rt/src/rtk_heading_node.cpp (167-167) Consider fully initializing the heading_status_ structure with appropriate default values rather than using an empty initializer list. This ensures all fields are properly initialized.
1 file skipped due to size limits:
  • eagleye_rt/src/monitor_node.cpp

💡 To request another review, post a new comment with "/windsurf-review".

if (
!velocity_scale_factor_.status.enabled_status &&
saved_vsf_estimater_number_ >= velocity_scale_factor_status_.estimated_number) {
std::ofstream csv_file(velocity_scale_factor_save_str_);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the issue below, there's no check if the file was successfully opened before proceeding.

Suggested change
std::ofstream csv_file(velocity_scale_factor_save_str_);
std::ofstream csv_file(velocity_scale_factor_save_str_);
if (!csv_file) {
RCLCPP_ERROR(this->get_logger(), "Failed to open file for writing: %s", velocity_scale_factor_save_str_.c_str());
}


private:
eagleye_msgs::msg::VelocityScaleFactor velocity_scale_factor_;
geometry_msgs::msg::TwistStamped velocity_;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The velocity_ member variable is declared but never assigned a value. There's no subscription or callback for the velocity topic that was present in the original code. This could lead to undefined behavior when velocity_ is used in the imuCallback method.

private:
eagleye_msgs::msg::VelocityScaleFactor velocity_scale_factor_;
geometry_msgs::msg::TwistStamped velocity_;
eagleye_msgs::msg::StatusStamped velocity_status_;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The velocity_status_ member variable is declared but never assigned a value. There's no subscription or callback for the velocity status topic that was present in the original code. This could cause issues when velocity_status_ is used in the imuCallback method, particularly when use_can_less_mode_ is true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant