Implement rm_dshot_shooter_controllers and update configurations#4
Implement rm_dshot_shooter_controllers and update configurations#4HydrogenZp merged 4 commits intoHydrogenZp:dshotfrom
Conversation
…ate related configurations.
…d comment out unused time variable in setDshotVelocity function.
There was a problem hiding this comment.
Code Review
This pull request introduces the rm_dshot_shooter_controllers package, which implements a shooter controller for RoboMaster robots with support for STOP, READY, PUSH, and BLOCK states. The code review identified several critical issues, including potential memory leaks from raw pointer usage, a compilation error due to C++20 features in a C++14 project, and a possible segmentation fault from missing bounds checks. Additional feedback focuses on improving code maintainability by removing unused variables, refactoring complex state transition logic, and ensuring documentation and package names are consistent throughout the repository.
| std::vector<std::vector<velocity_controllers::JointVelocityController*>> ctrls_friction_; | ||
| std::vector<std::vector<std::shared_ptr<control_toolbox::Pid>>> friction_pid_controllers_; | ||
| effort_controllers::JointPositionController ctrl_trigger_; | ||
| LowPassFilter* lp_filter_; | ||
| int push_per_rotation_{}, count_{}; | ||
| double push_wheel_speed_threshold_{}; | ||
| double freq_threshold_{}; | ||
| bool dynamic_reconfig_initialized_ = false; | ||
| bool state_changed_ = false; | ||
| bool enter_ready_ = false; | ||
| bool maybe_block_ = false; | ||
| int friction_block_count = 0; | ||
| bool last_friction_wheel_block = false, friction_wheel_block = false; | ||
| double friction_block_vel_{}; | ||
| double anti_friction_block_duty_cycle_{}, anti_friction_block_vel_{}; | ||
| bool has_shoot_ = false, has_shoot_last_ = false; | ||
| bool wheel_speed_drop_ = true; | ||
| double last_fricition_speed_{}; | ||
| double last_friction_change_speed_{}; | ||
|
|
||
| ros::Time last_shoot_time_, block_time_, last_block_time_; | ||
| enum | ||
| { | ||
| STOP, | ||
| READY, | ||
| PUSH, | ||
| BLOCK | ||
| }; | ||
| int state_ = STOP; | ||
| Config config_{}; | ||
| realtime_tools::RealtimeBuffer<Config> config_rt_buffer; | ||
| realtime_tools::RealtimeBuffer<rm_msgs::ShootCmd> cmd_rt_buffer_; | ||
| rm_msgs::ShootCmd cmd_; | ||
| std::shared_ptr<realtime_tools::RealtimePublisher<rm_msgs::LocalHeatState>> local_heat_state_pub_; | ||
| std::shared_ptr<realtime_tools::RealtimePublisher<rm_msgs::ShootState>> shoot_state_pub_; | ||
| std::vector<std::vector<std::unique_ptr<realtime_tools::RealtimePublisher<control_msgs::JointControllerState>>>> | ||
| friction_state_publishers_; | ||
| int loop_count_ = 0; | ||
| ros::Subscriber cmd_subscriber_; | ||
| dynamic_reconfigure::Server<rm_dshot_shooter_controllers::ShooterConfig>* d_srv_{}; |
There was a problem hiding this comment.
The class Controller manages several resources with raw pointers (ctrls_friction_ on line 94, lp_filter_ on line 97, and d_srv_ on line 133) which are allocated with new in init() but are never deallocated. This will cause memory leaks. Please use smart pointers (std::unique_ptr) to manage the lifecycle of these objects automatically.
For example:
std::vector<std::vector<velocity_controllers::JointVelocityController*>> ctrls_friction_;should becomestd::vector<std::vector<std::unique_ptr<velocity_controllers::JointVelocityController>>> ctrls_friction_;LowPassFilter* lp_filter_;should becomestd::unique_ptr<LowPassFilter> lp_filter_;dynamic_reconfigure::Server<...>* d_srv_{};should becomestd::unique_ptr<dynamic_reconfigure::Server<...>> d_srv_;
You will also need to update the allocation logic in standard.cpp to use std::make_unique or std::unique_ptr's constructor and std::move.
| config_ = { .block_effort = getParam(controller_nh, "block_effort", 0.), | ||
| .block_speed = getParam(controller_nh, "block_speed", 0.), | ||
| .block_duration = getParam(controller_nh, "block_duration", 0.), | ||
| .block_overtime = getParam(controller_nh, "block_overtime", 0.), | ||
| .anti_block_angle = getParam(controller_nh, "anti_block_angle", 0.), | ||
| .anti_block_threshold = getParam(controller_nh, "anti_block_threshold", 0.), | ||
| .forward_push_threshold = getParam(controller_nh, "forward_push_threshold", 0.1), | ||
| .exit_push_threshold = getParam(controller_nh, "exit_push_threshold", 0.1), | ||
| .extra_wheel_speed = getParam(controller_nh, "extra_wheel_speed", 0.), | ||
| .wheel_speed_drop_threshold = getParam(controller_nh, "wheel_speed_drop_threshold", 10.), | ||
| .wheel_speed_raise_threshold = getParam(controller_nh, "wheel_speed_raise_threshold", 3.1) }; |
There was a problem hiding this comment.
Designated initializers (e.g., .member = value) are used here to initialize the config_ struct. This is a C++20 feature, but the project is configured to use C++14 in CMakeLists.txt. This will cause a compilation error on compilers that strictly follow the C++14 standard. Please use aggregate initialization, which is compatible with C++14.
| config_ = { .block_effort = getParam(controller_nh, "block_effort", 0.), | |
| .block_speed = getParam(controller_nh, "block_speed", 0.), | |
| .block_duration = getParam(controller_nh, "block_duration", 0.), | |
| .block_overtime = getParam(controller_nh, "block_overtime", 0.), | |
| .anti_block_angle = getParam(controller_nh, "anti_block_angle", 0.), | |
| .anti_block_threshold = getParam(controller_nh, "anti_block_threshold", 0.), | |
| .forward_push_threshold = getParam(controller_nh, "forward_push_threshold", 0.1), | |
| .exit_push_threshold = getParam(controller_nh, "exit_push_threshold", 0.1), | |
| .extra_wheel_speed = getParam(controller_nh, "extra_wheel_speed", 0.), | |
| .wheel_speed_drop_threshold = getParam(controller_nh, "wheel_speed_drop_threshold", 10.), | |
| .wheel_speed_raise_threshold = getParam(controller_nh, "wheel_speed_raise_threshold", 3.1) }; | |
| config_ = { getParam(controller_nh, "block_effort", 0.), | |
| getParam(controller_nh, "block_speed", 0.), | |
| getParam(controller_nh, "block_duration", 0.), | |
| getParam(controller_nh, "block_overtime", 0.), | |
| getParam(controller_nh, "anti_block_angle", 0.), | |
| getParam(controller_nh, "anti_block_threshold", 0.), | |
| getParam(controller_nh, "forward_push_threshold", 0.1), | |
| getParam(controller_nh, "exit_push_threshold", 0.1), | |
| getParam(controller_nh, "extra_wheel_speed", 0.), | |
| getParam(controller_nh, "wheel_speed_drop_threshold", 10.), | |
| getParam(controller_nh, "wheel_speed_raise_threshold", 3.1) }; |
|
|
||
| void Controller::judgeBulletShoot(const ros::Time& time, const ros::Duration& period) | ||
| { | ||
| lp_filter_->input(ctrls_friction_[0][0]->joint_.getVelocity()); |
There was a problem hiding this comment.
The code directly accesses ctrls_friction_[0][0] without checking if the ctrls_friction_ vector and its nested vector are non-empty. If no friction wheels are configured in the YAML file, this will result in a segmentation fault. Please add checks to ensure these vectors are not empty before accessing their elements.
| @@ -0,0 +1,142 @@ | |||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
| Changelog for package rm_shooter_controllers | |||
There was a problem hiding this comment.
| velocity_controllers | ||
| effort_controllers | ||
| dynamic_reconfigure | ||
| LIBRARIES ${PROJECT_NAME} |
| int push_per_rotation_{}, count_{}; | ||
| double push_wheel_speed_threshold_{}; | ||
| double freq_threshold_{}; | ||
| bool dynamic_reconfig_initialized_ = false; | ||
| bool state_changed_ = false; | ||
| bool enter_ready_ = false; | ||
| bool maybe_block_ = false; | ||
| int friction_block_count = 0; | ||
| bool last_friction_wheel_block = false, friction_wheel_block = false; | ||
| double friction_block_vel_{}; | ||
| double anti_friction_block_duty_cycle_{}, anti_friction_block_vel_{}; | ||
| bool has_shoot_ = false, has_shoot_last_ = false; | ||
| bool wheel_speed_drop_ = true; | ||
| double last_fricition_speed_{}; | ||
| double last_friction_change_speed_{}; |
There was a problem hiding this comment.
There are several unused member variables in the Controller class. They should be removed to improve code clarity and reduce memory footprint.
The unused variables are:
count_(line 98)push_wheel_speed_threshold_(line 99)friction_block_count(line 105)last_friction_wheel_block,friction_wheel_block(line 106)friction_block_vel_(line 107)anti_friction_block_duty_cycle_,anti_friction_block_vel_(line 108)has_shoot_last_(line 109)wheel_speed_drop_(line 110)last_friction_change_speed_(line 112)
Please also remove their initializations in standard.cpp.
| controller_nh.getParam("friction", friction); | ||
| for (const auto& its : friction) | ||
| { | ||
| std::vector<double> wheel_speed_offset_temp; |
| if ((state_ != PUSH || cmd_.mode != READY) || | ||
| (cmd_.mode == READY && | ||
| (std::fmod(std::abs(ctrl_trigger_.command_struct_.position_ - ctrl_trigger_.getPosition()), 2. * M_PI) < | ||
| config_.exit_push_threshold || | ||
| cmd_.hz >= freq_threshold_))) |
| { | ||
| for (size_t j = 0; j < ctrls_friction_[i].size(); j++) | ||
| { | ||
| if (ctrls_friction_[i][j]->joint_.getVelocity() <= M_PI) |
There was a problem hiding this comment.
| if (j == 0) | ||
| { | ||
| target_speed = cmd_.wheel_speed + config_.extra_wheel_speed + cmd_.wheels_speed_offset_back; | ||
| } | ||
| else if (j == 1) | ||
| { | ||
| target_speed = cmd_.wheel_speed + config_.extra_wheel_speed + cmd_.wheels_speed_offset_front; | ||
| } |
There was a problem hiding this comment.
The logic for setting target_speed relies on the index j being 0 or 1. This is brittle and makes assumptions about the robot's hardware configuration (e.g., exactly two friction wheels per side, with specific roles for front and back). If more than two wheels are configured, target_speed will remain 0.0 for j > 1, which is a bug. Consider making this mapping from joint to speed offset configurable to make the controller more robust and generic.
No description provided.