3636
3737#include " MotorFailureSystem.hpp"
3838
39+ #include < algorithm>
3940#include < gz/plugin/Register.hh>
4041#include < gz/sim/components/JointVelocityCmd.hh>
4142#include < gz/sim/components/Name.hh>
@@ -98,13 +99,13 @@ void MotorFailureROS2System::Configure(const gz::sim::Entity &_entity,
9899 // Get model name to use as namespace
99100 std::string model_name = this ->model_ .Name (_ecm);
100101
101- // Get ROS2 topic name for motor failure number subscription
102+ // Get ROS2 topic name for motor failure ratios subscription
102103 if (_sdf->HasElement (" MotorFailureTopic" )) {
103104 this ->ros_topic_ = _sdf->Get <std::string>(" MotorFailureTopic" );
104105
105106 } else {
106107 // Use model name for topic naming
107- this ->ros_topic_ = " /" + model_name + " /motor_failure/motor_number " ;
108+ this ->ros_topic_ = " /" + model_name + " /motor_failure/ratios " ;
108109 }
109110
110111 // Initialize ROS2, if it has not already been initialized
@@ -118,9 +119,9 @@ void MotorFailureROS2System::Configure(const gz::sim::Entity &_entity,
118119 this ->ros_node_ = rclcpp::Node::make_shared (" motor_failure" );
119120
120121 // Create ROS2 subscription
121- this ->motor_failure_sub_ = this ->ros_node_ ->create_subscription <std_msgs::msg::Int32 >(
122+ this ->motor_failure_sub_ = this ->ros_node_ ->create_subscription <std_msgs::msg::Float32MultiArray >(
122123 this ->ros_topic_ , 10 ,
123- std::bind (&MotorFailureROS2System::MotorFailureNumberCallback , this , std::placeholders::_1));
124+ std::bind (&MotorFailureROS2System::MotorFailureRatiosCallback , this , std::placeholders::_1));
124125
125126 gzmsg << " [MotorFailureROS2System] Subscribed to ROS2 topic: " << this ->ros_topic_ << std::endl;
126127 gzmsg << " [MotorFailureROS2System] Initialized for model: " << model_name << std::endl;
@@ -192,38 +193,63 @@ void MotorFailureROS2System::FindMotorJoints(gz::sim::EntityComponentManager &_e
192193// ////////////////////////////////////////////////
193194void MotorFailureROS2System::ApplyMotorFailure (gz::sim::EntityComponentManager &_ecm)
194195{
195- int32_t current_failure ;
196+ std::vector< float > current_ratios ;
196197 {
197198 std::lock_guard<std::mutex> lock (this ->motor_failure_mutex_ );
198- current_failure = this ->motor_failure_number_ ;
199+ current_ratios = this ->motor_failure_ratios_ ;
199200 }
200201
201202 // Check if failure status changed
202- if (current_failure != this ->prev_motor_failure_number_ ) {
203- if (current_failure > 0 ) {
204- gzerr << " [MotorFailureROS2System] Motor " << current_failure << " failed!" << std::endl;
203+ if (current_ratios != this ->prev_motor_failure_ratios_ ) {
204+ for (size_t i = 0 ; i < current_ratios.size (); ++i) {
205+ float ratio = current_ratios[i];
206+ float prev = (i < this ->prev_motor_failure_ratios_ .size ()) ? this ->prev_motor_failure_ratios_ [i] : 0 .0f ;
205207
206- } else if (current_failure == 0 && this ->prev_motor_failure_number_ > 0 ) {
207- gzerr << " [MotorFailureROS2System] Motor " << this ->prev_motor_failure_number_
208- << " recovered!" << std::endl;
208+ if (ratio != prev) {
209+ if (ratio >= 1 .0f ) {
210+ gzerr << " [MotorFailureROS2System] Motor " << i << " completely failed!" << std::endl;
211+
212+ } else if (ratio > 0 .0f ) {
213+ gzerr << " [MotorFailureROS2System] Motor " << i << " degraded to "
214+ << (1 .0f - ratio) * 100 .0f << " % output" << std::endl;
215+
216+ } else {
217+ gzerr << " [MotorFailureROS2System] Motor " << i << " recovered!" << std::endl;
218+ }
219+ }
220+ }
221+
222+ // Check motors that were in the old list but not in the new (implicitly recovered)
223+ for (size_t i = current_ratios.size (); i < this ->prev_motor_failure_ratios_ .size (); ++i) {
224+ if (this ->prev_motor_failure_ratios_ [i] > 0 .0f ) {
225+ gzerr << " [MotorFailureROS2System] Motor " << i << " recovered!" << std::endl;
226+ }
209227 }
210228
211- this ->prev_motor_failure_number_ = current_failure ;
229+ this ->prev_motor_failure_ratios_ = current_ratios ;
212230 }
213231
214- // Apply motor failure if active (1-indexed from ROS2, convert to 0-indexed)
215- if (current_failure > 0 && current_failure <= static_cast < int32_t >( this ->motor_joints_ .size ()) ) {
216- int motorIdx = current_failure - 1 ;
217- Entity jointEntity = this -> motor_joints_ [motorIdx] ;
232+ // Apply per- motor failure ratios
233+ for ( size_t i = 0 ; i < this ->motor_joints_ .size (); ++i ) {
234+ float ratio = (i < current_ratios. size ()) ? current_ratios[i] : 0 . 0f ;
235+ ratio = std::clamp (ratio, 0 . 0f , 1 . 0f ) ;
218236
219- if (jointEntity != kNullEntity ) {
220- // Force joint velocity command to 0
221- // This is done in PreUpdate to override MulticopterMotorModel's commands
222- auto jointVelCmd = _ecm.Component <components::JointVelocityCmd>(jointEntity);
237+ if (ratio <= 0 .0f ) {
238+ continue ;
239+ }
223240
224- if (jointVelCmd) {
225- *jointVelCmd = components::JointVelocityCmd ({0.0 });
226- }
241+ Entity jointEntity = this ->motor_joints_ [i];
242+
243+ if (jointEntity == kNullEntity ) {
244+ continue ;
245+ }
246+
247+ auto jointVelCmd = _ecm.Component <components::JointVelocityCmd>(jointEntity);
248+
249+ if (jointVelCmd) {
250+ double current = jointVelCmd->Data ()[0 ];
251+ double degraded = current * (1.0 - static_cast <double >(ratio));
252+ *jointVelCmd = components::JointVelocityCmd ({degraded});
227253 }
228254 }
229255}
@@ -253,12 +279,12 @@ void MotorFailureROS2System::PreUpdate(const gz::sim::UpdateInfo &_info,
253279}
254280
255281// ////////////////////////////////////////////////
256- void MotorFailureROS2System::MotorFailureNumberCallback (const std_msgs::msg::Int32 ::SharedPtr _msg)
282+ void MotorFailureROS2System::MotorFailureRatiosCallback (const std_msgs::msg::Float32MultiArray ::SharedPtr _msg)
257283{
258284 std::lock_guard<std::mutex> lock (this ->motor_failure_mutex_ );
259- this ->motor_failure_number_ = _msg->data ;
260- gzdbg << " [MotorFailureROS2System] Received motor failure number : "
261- << this ->motor_failure_number_ << std::endl;
285+ this ->motor_failure_ratios_ = _msg->data ;
286+ gzdbg << " [MotorFailureROS2System] Received motor failure ratios, size : "
287+ << this ->motor_failure_ratios_ . size () << std::endl;
262288}
263289
264290// Register the plugin
0 commit comments