mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-06-01 02:55:07 +08:00
Add Gazebo MotorFailure Plugin (#25776)
Build all targets / Scan for Board Targets (push) Has been cancelled
Build all targets / Build [${{ matrix.runner }}][${{ matrix.group }}] (push) Has been cancelled
Build all targets / Upload Artifacts (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_fmu-v5_default) (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_sitl_default) (push) Has been cancelled
Checks / build (check_format) (push) Has been cancelled
Checks / build (check_newlines) (push) Has been cancelled
Checks / build (module_documentation) (push) Has been cancelled
Checks / build (px4_fmu-v2_default stack_check) (push) Has been cancelled
Checks / build (px4_sitl_allyes) (push) Has been cancelled
Checks / build (shellcheck_all) (push) Has been cancelled
Checks / build (tests) (push) Has been cancelled
Checks / build (tests_coverage) (push) Has been cancelled
Checks / build (validate_module_configs) (push) Has been cancelled
Clang Tidy / build (push) Has been cancelled
MacOS build / build (px4_fmu-v5_default) (push) Has been cancelled
MacOS build / build (px4_sitl) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:22.04) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:24.04) (push) Has been cancelled
Container build / Set Tags and Variables (push) Has been cancelled
Container build / Build Container (amd64) (push) Has been cancelled
Container build / Build Container (arm64) (push) Has been cancelled
Container build / Deploy To Registry (push) Has been cancelled
EKF Update Change Indicator / unit_tests (push) Has been cancelled
Failsafe Simulator Build / build (failsafe_web) (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v5x (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v6x (push) Has been cancelled
FLASH usage analysis / Publish Results (push) Has been cancelled
ITCM check / Checking nxp_mr-tropic (push) Has been cancelled
ITCM check / Checking nxp_tropic-community (push) Has been cancelled
ITCM check / Checking px4_fmu-v5x (push) Has been cancelled
ITCM check / Checking px4_fmu-v6xrt (push) Has been cancelled
MAVROS Mission Tests / build (map[mission:MC_mission_box vehicle:iris]) (push) Has been cancelled
MAVROS Offboard Tests / build (map[test_file:mavros_posix_tests_offboard_posctl.test vehicle:iris]) (push) Has been cancelled
Nuttx Target with extra env config / build (px4_fmu-v5_default) (push) Has been cancelled
Python CI Checks / build (push) Has been cancelled
ROS Integration Tests / build (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:humble ubuntu:jammy]) (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:jazzy ubuntu:noble]) (push) Has been cancelled
SITL Tests / Testing PX4 tailsitter (push) Has been cancelled
SITL Tests / Testing PX4 iris (push) Has been cancelled
SITL Tests / Testing PX4 standard_vtol (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / build (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / deploy (push) Has been cancelled
Build all targets / Scan for Board Targets (push) Has been cancelled
Build all targets / Build [${{ matrix.runner }}][${{ matrix.group }}] (push) Has been cancelled
Build all targets / Upload Artifacts (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_fmu-v5_default) (push) Has been cancelled
Checks / build (NO_NINJA_BUILD=1 px4_sitl_default) (push) Has been cancelled
Checks / build (check_format) (push) Has been cancelled
Checks / build (check_newlines) (push) Has been cancelled
Checks / build (module_documentation) (push) Has been cancelled
Checks / build (px4_fmu-v2_default stack_check) (push) Has been cancelled
Checks / build (px4_sitl_allyes) (push) Has been cancelled
Checks / build (shellcheck_all) (push) Has been cancelled
Checks / build (tests) (push) Has been cancelled
Checks / build (tests_coverage) (push) Has been cancelled
Checks / build (validate_module_configs) (push) Has been cancelled
Clang Tidy / build (push) Has been cancelled
MacOS build / build (px4_fmu-v5_default) (push) Has been cancelled
MacOS build / build (px4_sitl) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:22.04) (push) Has been cancelled
Ubuntu environment build / Build and Test (ubuntu:24.04) (push) Has been cancelled
Container build / Set Tags and Variables (push) Has been cancelled
Container build / Build Container (amd64) (push) Has been cancelled
Container build / Build Container (arm64) (push) Has been cancelled
Container build / Deploy To Registry (push) Has been cancelled
EKF Update Change Indicator / unit_tests (push) Has been cancelled
Failsafe Simulator Build / build (failsafe_web) (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v5x (push) Has been cancelled
FLASH usage analysis / Analyzing px4_fmu-v6x (push) Has been cancelled
FLASH usage analysis / Publish Results (push) Has been cancelled
ITCM check / Checking nxp_mr-tropic (push) Has been cancelled
ITCM check / Checking nxp_tropic-community (push) Has been cancelled
ITCM check / Checking px4_fmu-v5x (push) Has been cancelled
ITCM check / Checking px4_fmu-v6xrt (push) Has been cancelled
MAVROS Mission Tests / build (map[mission:MC_mission_box vehicle:iris]) (push) Has been cancelled
MAVROS Offboard Tests / build (map[test_file:mavros_posix_tests_offboard_posctl.test vehicle:iris]) (push) Has been cancelled
Nuttx Target with extra env config / build (px4_fmu-v5_default) (push) Has been cancelled
Python CI Checks / build (push) Has been cancelled
ROS Integration Tests / build (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:humble ubuntu:jammy]) (push) Has been cancelled
ROS Translation Node Tests / Build and test (map[ros_version:jazzy ubuntu:noble]) (push) Has been cancelled
SITL Tests / Testing PX4 tailsitter (push) Has been cancelled
SITL Tests / Testing PX4 iris (push) Has been cancelled
SITL Tests / Testing PX4 standard_vtol (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / build (push) Has been cancelled
Docs - Deploy PX4 User Guide to AWS / deploy (push) Has been cancelled
* Add Gazebo MotorFailure Plugin * switch from ROS2 to Gazebo Transport * Clean up old/dead comments, Refactor variable * gz: submodule update
This commit is contained in:
+1
-1
Submodule Tools/simulation/gz updated: ee3835184c...e34154fd1d
@@ -70,11 +70,12 @@ if (gz-transport_FOUND)
|
|||||||
add_subdirectory(generic_motor)
|
add_subdirectory(generic_motor)
|
||||||
add_subdirectory(buoyancy)
|
add_subdirectory(buoyancy)
|
||||||
add_subdirectory(spacecraft_thruster)
|
add_subdirectory(spacecraft_thruster)
|
||||||
|
add_subdirectory(motor_failure)
|
||||||
|
|
||||||
# Add an alias target for each plugin
|
# Add an alias target for each plugin
|
||||||
if (TARGET GstCameraSystem)
|
if (TARGET GstCameraSystem)
|
||||||
add_custom_target(px4_gz_plugins ALL DEPENDS OpticalFlowSystem MovingPlatformController TemplatePlugin GenericMotorModelPlugin BuoyancySystemPlugin GstCameraSystem SpacecraftThrusterModelPlugin)
|
add_custom_target(px4_gz_plugins ALL DEPENDS OpticalFlowSystem MovingPlatformController TemplatePlugin GenericMotorModelPlugin BuoyancySystemPlugin GstCameraSystem SpacecraftThrusterModelPlugin MotorFailurePlugin)
|
||||||
else()
|
else()
|
||||||
add_custom_target(px4_gz_plugins ALL DEPENDS OpticalFlowSystem MovingPlatformController TemplatePlugin GenericMotorModelPlugin BuoyancySystemPlugin SpacecraftThrusterModelPlugin)
|
add_custom_target(px4_gz_plugins ALL DEPENDS OpticalFlowSystem MovingPlatformController TemplatePlugin GenericMotorModelPlugin BuoyancySystemPlugin SpacecraftThrusterModelPlugin MotorFailurePlugin)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
############################################################################
|
||||||
|
#
|
||||||
|
# Copyright (c) 2025 PX4 Development Team. All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in
|
||||||
|
# the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
# 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
# used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
project(MotorFailurePlugin)
|
||||||
|
|
||||||
|
add_library(${PROJECT_NAME} SHARED
|
||||||
|
MotorFailureSystem.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
PUBLIC px4_gz_msgs
|
||||||
|
PUBLIC ${GZ_SENSORS_TARGET}
|
||||||
|
PUBLIC ${GZ_PLUGIN_TARGET}
|
||||||
|
PUBLIC ${GZ_SIM_TARGET}
|
||||||
|
PUBLIC ${GZ_TRANSPORT_TARGET}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(${PROJECT_NAME}
|
||||||
|
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
PUBLIC px4_gz_msgs
|
||||||
|
)
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "MotorFailureSystem.hpp"
|
||||||
|
|
||||||
|
#include <gz/plugin/Register.hh>
|
||||||
|
#include <gz/sim/components/JointVelocityCmd.hh>
|
||||||
|
#include <gz/sim/components/Name.hh>
|
||||||
|
#include <gz/sim/Model.hh>
|
||||||
|
#include <gz/sim/Util.hh>
|
||||||
|
|
||||||
|
using namespace gz;
|
||||||
|
using namespace sim;
|
||||||
|
using namespace systems;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
void MotorFailureSystem::Configure(const Entity &_entity,
|
||||||
|
const std::shared_ptr<const sdf::Element> &_sdf,
|
||||||
|
EntityComponentManager &_ecm,
|
||||||
|
EventManager &/*_eventMgr*/)
|
||||||
|
{
|
||||||
|
this->_model = Model(_entity);
|
||||||
|
this->_model_entity = _entity;
|
||||||
|
|
||||||
|
if (!this->_model.Valid(_ecm)) {
|
||||||
|
gzerr << "[MotorFailureSystem] plugin should be attached to a model "
|
||||||
|
<< "entity. Failed to initialize." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get model name to use as namespace
|
||||||
|
std::string model_name = this->_model.Name(_ecm);
|
||||||
|
|
||||||
|
// Get Gazebo Transport topic name for motor failure number subscription
|
||||||
|
if (_sdf->HasElement("MotorFailureTopic")) {
|
||||||
|
this->_gz_topic = _sdf->Get<std::string>("MotorFailureTopic");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Use Gazebo model-scoped topic naming convention
|
||||||
|
this->_gz_topic = "/model/" + model_name + "/motor_failure/motor_number";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to Gazebo Transport topic
|
||||||
|
if (!this->_node.Subscribe(this->_gz_topic, &MotorFailureSystem::MotorFailureNumberCallback, this)) {
|
||||||
|
gzerr << "[MotorFailureSystem] Error subscribing to topic [" << this->_gz_topic << "]" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzmsg << "[MotorFailureSystem] Subscribed to Gazebo Transport topic: " << this->_gz_topic << std::endl;
|
||||||
|
gzmsg << "[MotorFailureSystem] Initialized for model: " << model_name << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
void MotorFailureSystem::FindMotorJoints(EntityComponentManager &_ecm)
|
||||||
|
{
|
||||||
|
if (this->_joints_found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all joints with "rotor_X_joint" pattern
|
||||||
|
this->_motor_joints.clear();
|
||||||
|
|
||||||
|
// Get all joints in the model
|
||||||
|
auto joints = this->_model.Joints(_ecm);
|
||||||
|
|
||||||
|
// Regular expression to match rotor joints (e.g., "rotor_0_joint", "rotor_1_joint")
|
||||||
|
std::regex motorPattern("rotor_(\\d+)_joint");
|
||||||
|
std::smatch match;
|
||||||
|
|
||||||
|
// Find rotor joints and sort by motor number
|
||||||
|
std::map<int, Entity> motorMap;
|
||||||
|
|
||||||
|
for (const auto &joint : joints) {
|
||||||
|
auto nameComp = _ecm.Component<components::Name>(joint);
|
||||||
|
|
||||||
|
if (nameComp) {
|
||||||
|
std::string jointName = nameComp->Data();
|
||||||
|
|
||||||
|
// Try to match the joint name against the pattern
|
||||||
|
if (std::regex_match(jointName, match, motorPattern)) {
|
||||||
|
// Extract motor number from the first capture group
|
||||||
|
try {
|
||||||
|
int motorNumber = std::stoi(match[1].str());
|
||||||
|
motorMap[motorNumber] = joint;
|
||||||
|
gzdbg << "[MotorFailureSystem] Found motor " << motorNumber
|
||||||
|
<< ": " << jointName << std::endl;
|
||||||
|
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
gzwarn << "[MotorFailureSystem] Failed to parse motor number from: "
|
||||||
|
<< jointName << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert map to vector for indexed access
|
||||||
|
for (const auto &pair : motorMap) {
|
||||||
|
// Ensure vector is large enough
|
||||||
|
if (pair.first >= static_cast<int>(this->_motor_joints.size())) {
|
||||||
|
this->_motor_joints.resize(pair.first + 1, kNullEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_motor_joints[pair.first] = pair.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->_motor_joints.empty()) {
|
||||||
|
gzmsg << "[MotorFailureSystem] Found " << this->_motor_joints.size()
|
||||||
|
<< " motor joints" << std::endl;
|
||||||
|
this->_joints_found = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
gzwarn << "[MotorFailureSystem] No motor joints found in model" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
void MotorFailureSystem::ApplyMotorFailure(EntityComponentManager &_ecm)
|
||||||
|
{
|
||||||
|
int32_t current_failure;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(this->_motor_failure_mutex);
|
||||||
|
current_failure = this->_motor_failure_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if failure status changed
|
||||||
|
if (current_failure != this->_prev_motor_failure_number) {
|
||||||
|
if (current_failure > 0) {
|
||||||
|
gzerr << "[MotorFailureSystem] Motor " << current_failure << " failed!" << std::endl;
|
||||||
|
|
||||||
|
} else if (current_failure == 0 && this->_prev_motor_failure_number > 0) {
|
||||||
|
gzerr << "[MotorFailureSystem] Motor " << this->_prev_motor_failure_number
|
||||||
|
<< " recovered!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->_prev_motor_failure_number = current_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply motor failure if active (1-indexed motor number, convert to 0-indexed)
|
||||||
|
if (current_failure > 0 && current_failure <= static_cast<int32_t>(this->_motor_joints.size())) {
|
||||||
|
int motorIdx = current_failure - 1;
|
||||||
|
Entity jointEntity = this->_motor_joints[motorIdx];
|
||||||
|
|
||||||
|
if (jointEntity != kNullEntity) {
|
||||||
|
// Force joint velocity command to 0
|
||||||
|
// This is done in PreUpdate to override MulticopterMotorModel's commands
|
||||||
|
auto jointVelCmd = _ecm.Component<components::JointVelocityCmd>(jointEntity);
|
||||||
|
|
||||||
|
if (jointVelCmd) {
|
||||||
|
*jointVelCmd = components::JointVelocityCmd({0.0});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
void MotorFailureSystem::PreUpdate(const UpdateInfo &_info,
|
||||||
|
EntityComponentManager &_ecm)
|
||||||
|
{
|
||||||
|
// Skip if paused
|
||||||
|
if (_info.paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find motor joints on first update
|
||||||
|
if (!this->_joints_found) {
|
||||||
|
this->FindMotorJoints(_ecm);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this->ApplyMotorFailure(const_cast<EntityComponentManager &>(_ecm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
void MotorFailureSystem::MotorFailureNumberCallback(const gz::msgs::Int32 &_msg)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(this->_motor_failure_mutex);
|
||||||
|
this->_motor_failure_number = _msg.data();
|
||||||
|
gzdbg << "[MotorFailureSystem] Received motor failure number: "
|
||||||
|
<< this->_motor_failure_number << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the plugin
|
||||||
|
GZ_ADD_PLUGIN(
|
||||||
|
MotorFailureSystem,
|
||||||
|
gz::sim::System,
|
||||||
|
MotorFailureSystem::ISystemConfigure,
|
||||||
|
MotorFailureSystem::ISystemPreUpdate
|
||||||
|
)
|
||||||
|
|
||||||
|
GZ_ADD_PLUGIN_ALIAS(MotorFailureSystem,
|
||||||
|
"gz::sim::systems::MotorFailureSystem")
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef GZ_SIM_SYSTEMS_MOTORFAILURESYSTEM_HPP_
|
||||||
|
#define GZ_SIM_SYSTEMS_MOTORFAILURESYSTEM_HPP_
|
||||||
|
|
||||||
|
#include <gz/sim/System.hh>
|
||||||
|
#include <gz/sim/Model.hh>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
#include <map>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
// Gazebo Transport includes
|
||||||
|
#include <gz/transport/Node.hh>
|
||||||
|
#include <gz/msgs/int32.pb.h>
|
||||||
|
|
||||||
|
namespace gz
|
||||||
|
{
|
||||||
|
namespace sim
|
||||||
|
{
|
||||||
|
// Inline bracket to help doxygen filtering.
|
||||||
|
inline namespace GZ_SIM_VERSION_NAMESPACE
|
||||||
|
{
|
||||||
|
namespace systems
|
||||||
|
{
|
||||||
|
|
||||||
|
/// \brief This system subscribes to a Gazebo Transport topic to receive motor failure
|
||||||
|
/// commands and directly controls motor joints to simulate failures.
|
||||||
|
/// This allows simulating motor failures in multirotor vehicles.
|
||||||
|
class MotorFailureSystem:
|
||||||
|
public System,
|
||||||
|
public ISystemConfigure,
|
||||||
|
public ISystemPreUpdate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Documentation inherited
|
||||||
|
void Configure(const Entity &_entity,
|
||||||
|
const std::shared_ptr<const sdf::Element> &_sdf,
|
||||||
|
EntityComponentManager &_ecm,
|
||||||
|
EventManager &_eventMgr) override;
|
||||||
|
|
||||||
|
// Documentation inherited
|
||||||
|
void PreUpdate(const gz::sim::UpdateInfo &_info,
|
||||||
|
gz::sim::EntityComponentManager &_ecm) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// \brief Callback for Gazebo Transport motor failure number subscription
|
||||||
|
void MotorFailureNumberCallback(const gz::msgs::Int32 &_msg);
|
||||||
|
|
||||||
|
/// \brief Find all motor joints in the model
|
||||||
|
void FindMotorJoints(gz::sim::EntityComponentManager &_ecm);
|
||||||
|
|
||||||
|
/// \brief Apply motor failure (set velocity to 0)
|
||||||
|
void ApplyMotorFailure(gz::sim::EntityComponentManager &_ecm);
|
||||||
|
|
||||||
|
/// \brief Gazebo Transport node for communication
|
||||||
|
gz::transport::Node _node;
|
||||||
|
|
||||||
|
/// \brief Model entity
|
||||||
|
gz::sim::Entity _model_entity;
|
||||||
|
|
||||||
|
/// \brief Model interface
|
||||||
|
gz::sim::Model _model;
|
||||||
|
|
||||||
|
/// \brief Vector of motor joint entities (indexed by motor number)
|
||||||
|
std::vector<gz::sim::Entity> _motor_joints;
|
||||||
|
|
||||||
|
/// \brief Current motor failure number (-1 or 0 means no failure, 1-indexed motor number)
|
||||||
|
int32_t _motor_failure_number{-1};
|
||||||
|
|
||||||
|
/// \brief Previous motor failure number to detect changes
|
||||||
|
int32_t _prev_motor_failure_number{-1};
|
||||||
|
|
||||||
|
/// \brief Gazebo Transport topic name for subscribing to motor failure commands
|
||||||
|
/// Defaults to /model/<model_name>/motor_failure/motor_number if not specified in SDF
|
||||||
|
std::string _gz_topic{"/motor_failure/motor_number"};
|
||||||
|
|
||||||
|
/// \brief Mutex to protect _motor_failure_number
|
||||||
|
std::mutex _motor_failure_mutex;
|
||||||
|
|
||||||
|
/// \brief Flag to indicate if motor joints have been found
|
||||||
|
bool _joints_found{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace systems
|
||||||
|
} // namespace GZ_SIM_VERSION_NAMESPACE
|
||||||
|
} // namespace sim
|
||||||
|
} // namespace gz
|
||||||
|
|
||||||
|
#endif // GZ_SIM_SYSTEMS_MOTORFAILURESYSTEM_HPP_
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# Motor Failure System Plugin
|
||||||
|
|
||||||
|
This Gazebo plugin enables motor failure simulation for multirotor vehicles in PX4 SITL.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Motor Failure System plugin subscribes to a Gazebo Transport topic to receive motor failure commands and directly controls motor joints to simulate failures. This allows simulating motor failures during flight testing.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Gazebo Transport integration for receiving motor failure commands
|
||||||
|
- Automatic detection of motor joints (rotor_0_joint, rotor_1_joint, etc.)
|
||||||
|
- Direct joint velocity override in PreUpdate cycle
|
||||||
|
- Thread-safe motor failure number handling
|
||||||
|
- Configurable topic names via SDF
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### SDF Parameters
|
||||||
|
|
||||||
|
- `<MotorFailureTopic>` (optional): Gazebo Transport topic for receiving motor failure commands
|
||||||
|
- Default: `/model/<model_name>/motor_failure/motor_number`
|
||||||
|
- Follows Gazebo model-scoped topic naming convention
|
||||||
|
- If specified: Uses the exact topic name provided
|
||||||
|
|
||||||
|
### Example SDF Usage
|
||||||
|
|
||||||
|
**IMPORTANT**: The MotorFailureSystem plugin must be declared **AFTER** the `gz-sim-multicopter-motor-model-system` plugin in your SDF file. This ensures the motor failure override runs after the motor model sets its velocity commands.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- First: Motor model plugin -->
|
||||||
|
<plugin
|
||||||
|
filename="gz-sim-multicopter-motor-model-system"
|
||||||
|
name="gz::sim::systems::MulticopterMotorModel">
|
||||||
|
<!-- motor model configuration -->
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Second: Motor failure plugin (must come after motor model) -->
|
||||||
|
|
||||||
|
<!-- Minimal configuration (uses model name as namespace) -->
|
||||||
|
<plugin
|
||||||
|
filename="MotorFailurePlugin"
|
||||||
|
name="gz::sim::systems::MotorFailureSystem">
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Custom topic name -->
|
||||||
|
<plugin
|
||||||
|
filename="MotorFailurePlugin"
|
||||||
|
name="gz::sim::systems::MotorFailureSystem">
|
||||||
|
<MotorFailureTopic>/custom/topic/name</MotorFailureTopic>
|
||||||
|
</plugin>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Publishing Motor Failure Commands
|
||||||
|
|
||||||
|
To trigger a motor failure, publish a message to the Gazebo Transport topic.
|
||||||
|
|
||||||
|
For a vehicle with namespace `x500_0`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fail motor 1 (motors are 1-indexed: 1, 2, 3, 4, ...)
|
||||||
|
gz topic -t /model/x500_0/motor_failure/motor_number -m gz.msgs.Int32 -p "data: 1"
|
||||||
|
|
||||||
|
# Clear motor failure (restore normal operation)
|
||||||
|
gz topic -t /model/x500_0/motor_failure/motor_number -m gz.msgs.Int32 -p "data: 0"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Replace `x500_0` with your vehicle's model name.
|
||||||
|
|
||||||
|
**Motor Numbering**:
|
||||||
|
- Motors are **1-indexed**: 1, 2, 3, 4, etc.
|
||||||
|
- `data: 0` clears the motor failure
|
||||||
|
- `data: -1` also clears the motor failure
|
||||||
|
|
||||||
|
### Monitoring Motor Failure Status
|
||||||
|
|
||||||
|
You can monitor the motor failure messages in the Gazebo console output.
|
||||||
|
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- The plugin applies motor failure in the PreUpdate cycle by setting joint velocity to 0
|
||||||
|
- **Plugin Declaration Order**: This plugin must be declared AFTER the MulticopterMotorModel plugin in the SDF file to ensure proper execution order
|
||||||
Reference in New Issue
Block a user