Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Space bots isr/pr spacecraft reversible motors #2790

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f3421a2
feat: added support for spacecraft thrusters
Pedro-Roque Jun 3, 2024
b22c8b2
rft: codechecked
Pedro-Roque Jun 4, 2024
24841e9
doc: adding basic tutorial with short description
Pedro-Roque Jun 4, 2024
9d88cdf
doc: improved comment regarding the method
Pedro-Roque Jun 4, 2024
3c802b5
fix: naming on comment
Pedro-Roque Jun 4, 2024
a8f08f1
fix: addressed request changes for PR
Pedro-Roque Jun 6, 2024
4e60a6f
doc: image reference change on tutorials/spacecraft_thrusters.md
Pedro-Roque Jun 5, 2024
05d5a6d
feat: added world with spacecraft example and dart model
Pedro-Roque Jun 7, 2024
52c1505
rft: moved mesh to fuel
Pedro-Roque Jun 7, 2024
dfa7fe1
fix: linting and dart version in SDF
Pedro-Roque Jun 10, 2024
95a397b
feat: added world with spacecraft example and dart model
Pedro-Roque Jun 10, 2024
4e5dd59
rft: moved mesh to fuel
Pedro-Roque Jun 7, 2024
8168609
fix: unmerged file
Pedro-Roque Jun 10, 2024
727b4ee
doc: fixed wrong doc instruction
Pedro-Roque Jun 10, 2024
cd7d2a4
feat: added world with spacecraft example and dart model
Pedro-Roque Jun 7, 2024
1a02dec
rft: moved mesh to fuel
Pedro-Roque Jun 7, 2024
13dd82a
fix: lint issue on plugin source file
Pedro-Roque Jun 10, 2024
bf7c966
fix: linting issues on tutorial file
Pedro-Roque Jun 10, 2024
d4c7530
fix: documentation and removed not used arguments
Pedro-Roque Jun 11, 2024
4689215
doc: removed trailing whitespaces
Pedro-Roque Jun 11, 2024
95f5231
doc: fixed line lengths
Pedro-Roque Jun 11, 2024
d48bcf1
doc: ... and removing trailing spaces again ...
Pedro-Roque Jun 11, 2024
6250a96
Some suggested changes (#1)
bperseghetti Jun 13, 2024
0c458e1
rft: fix building and cleaning unnecessary headers
Pedro-Roque Jun 13, 2024
11f4e42
feat: added 2D spacecraft simulation
Pedro-Roque Jun 13, 2024
9bed3ec
doc: updated documentation for 2D spacecraft simulator
Pedro-Roque Jun 13, 2024
6ef6b60
fix: trailing whitespace
Pedro-Roque Jun 13, 2024
d7e247f
add: unit test for spacecraft thrusters
Pedro-Roque Jul 17, 2024
dc2abc9
fix: bug on target 0.0 duty cycle
Pedro-Roque Jul 17, 2024
0a36b22
fix: linting
Pedro-Roque Jul 17, 2024
d2db67c
lint: shrank one line
Pedro-Roque Jul 17, 2024
e3ad96f
test: enabling for windows
Pedro-Roque Jul 18, 2024
c9678b5
revert: keep ignoring windows testing
Pedro-Roque Jul 18, 2024
3b5217c
fix: changed motor_speed to duty_cycle for clarity
Pedro-Roque Jul 18, 2024
9127aef
Merge remote-tracking branch 'origin/gz-sim7' into pr-spacecraft-thru…
Pedro-Roque Jul 19, 2024
ae04a1c
feat(ReversibleMultiCopterMotorModel): Created a simplistic model for…
andre-rebelo-teixeira Nov 13, 2024
b0b2bbf
fix(ReversibleMotor): Update to third order system to be closer to th…
andre-rebelo-teixeira Nov 16, 2024
09e7dbb
Merge pull request #1 from gazebosim/gz-sim7
andre-rebelo-teixeira Feb 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/systems/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ add_subdirectory(performer_detector)
add_subdirectory(perfect_comms)
add_subdirectory(physics)
add_subdirectory(pose_publisher)
add_subdirectory(reversible_rotor_motor)
add_subdirectory(rf_comms)
add_subdirectory(scene_broadcaster)
add_subdirectory(sensors)
Expand Down
7 changes: 7 additions & 0 deletions src/systems/reversible_rotor_motor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
gz_add_system(reversible-multicopter-motor-model
SOURCES
ReversibleMulticopterMotorModel.cc
PUBLIC_LINK_LIBS
gz-common${GZ_COMMON_VER}::gz-common${GZ_COMMON_VER}
gz-transport${GZ_TRANSPORT_VER}::gz-transport${GZ_TRANSPORT_VER}
)
11 changes: 11 additions & 0 deletions src/systems/reversible_rotor_motor/PX4.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"folders": [
{
"path": "../../../../../../PX4"
},
{
"path": "../../../../.."
}
],
"settings": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
#include "ReversibleMulticopterMotorModel.hh"

#include <mutex>
#include <string>

#include <gz/msgs/actuators.pb.h>

#include <gz/common/Profiler.hh>

#include <gz/plugin/Register.hh>
#include <gz/transport/Node.hh>

#include <gz/math/Helpers.hh>
#include <gz/math/Pose3.hh>
#include <gz/math/Vector3.hh>
#include <gz/msgs/Utility.hh>

#include <sdf/sdf.hh>

#include "gz/sim/components/Actuators.hh"
#include "gz/sim/components/ExternalWorldWrenchCmd.hh"
#include "gz/sim/components/JointAxis.hh"
#include "gz/sim/components/JointVelocity.hh"
#include "gz/sim/components/JointVelocityCmd.hh"
#include "gz/sim/components/LinearVelocity.hh"
#include "gz/sim/components/ParentLinkName.hh"
#include "gz/sim/components/Pose.hh"
#include "gz/sim/components/Wind.hh"
#include "gz/sim/Link.hh"
#include "gz/sim/Model.hh"
#include "gz/sim/Util.hh"

using namespace gz;
using namespace sim;
using namespace systems;

class gz::sim::systems::ReversibleMulticopterMotorModelPrivate
{
public: void OnActuatorMsg(const msgs::Actuators &_msg);
public: void UpdateForcesAndMoments(EntityComponentManager &_ecm);
public: Entity jointEntity;
public: Entity linkEntity;
public: Entity parentLinkEntity;
public: std::string jointName = "";
public: std::string linkName = "";
public: std::string parentLinkName = "";
public: Model model{kNullEntity};
public: std::string robot_name = "";
public: std::string commandSubTopic = "";
public: int motorNumber = 0;
public: double maxRotVelocity = 838.0;
public: double motorInputVel = 0.0;
public: double simVelSlowDown = 10.0;

public: std::vector<double> TorquePolynomial = {0.0, 0.0, 0.0, 0.0};
public: std::vector<double> ThrustPolynomial = {0.0, 0.0, 0.0, 0.0};

public: std::optional<msgs::Actuators> recvdActuatorsMsg;
public: std::mutex recvdActuatorsMsgMutex;
public: transport::Node node;
};

ReversibleMulticopterMotorModel::ReversibleMulticopterMotorModel()
: dataPtr(std::make_unique<ReversibleMulticopterMotorModelPrivate>())
{
}

void ReversibleMulticopterMotorModel::Configure(const Entity &_entity,
const std::shared_ptr<const sdf::Element> &_sdf,
EntityComponentManager &_ecm,
EventManager &/*_eventMgr*/)
{
this->dataPtr->model = Model(_entity);

if (!this->dataPtr->model.Valid(_ecm))
{
gzerr << "ReversibleMulticopterMotorModel plugin should be attached to a model "
<< "entity. Failed to initialize." << std::endl;
return;
}

auto sdfClone = _sdf->Clone();

if(sdfClone->HasElement("robotName")){
std::string robotName = sdfClone->Get<std::string>("robotName");
this->dataPtr->robot_name = robotName;
}else{
this->dataPtr->robot_name = "default_robot";
gzerr << "robotName not specified, using default_robot.\n";
}

if (sdfClone->HasElement("jointName"))
{
dataPtr->jointName = sdfClone->Get<std::string>("jointName");
dataPtr->jointEntity = this->dataPtr->model.JointByName(_ecm, dataPtr->jointName);
}

if (sdfClone->HasElement("linkName"))
{
dataPtr->linkName = sdfClone->Get<std::string>("linkName");
dataPtr->linkEntity = this->dataPtr->model.LinkByName(_ecm, dataPtr->linkName);
}

if (sdfClone->HasElement("commandSubTopic"))
{
this->dataPtr->commandSubTopic = sdfClone->Get<std::string>("commandSubTopic");
}

if (sdfClone->HasElement("motorNumber"))
{
this->dataPtr->motorNumber = sdfClone->Get<unsigned int>("motorNumber");
} else {
this->dataPtr->motorNumber = 0;
gzerr << "motorNumber not specified, using 0.\n";
}

if (this->dataPtr->jointName != "") {
dataPtr->parentLinkName = _ecm.Component<components::ParentLinkName>(dataPtr->jointEntity)->Data();
dataPtr->parentLinkEntity = dataPtr->model.LinkByName(_ecm, dataPtr->parentLinkName);
}

auto a0Thrust = sdfClone->Get<double>("a0ThrustConstant");
auto a1Thrust = sdfClone->Get<double>("a1ThrustConstant");
auto a2Thrust = sdfClone->Get<double>("a2ThrustConstant");
auto a3Thrust = sdfClone->Get<double>("a3ThrustConstant");

this->dataPtr->ThrustPolynomial = {a0Thrust, a1Thrust, a2Thrust, a3Thrust};

auto a0Torque = sdfClone->Get<double>("a0TorqueConstant");
auto a1Torque = sdfClone->Get<double>("a1TorqueConstant");
auto a2Torque = sdfClone->Get<double>("a2TorqueConstant");
auto a3Torque = sdfClone->Get<double>("a3TorqueConstant");

this->dataPtr->TorquePolynomial = {a0Torque, a1Torque, a2Torque, a3Torque};


dataPtr->simVelSlowDown = sdfClone->Get<double>("simVelSlowDown");

std::string topic = transport::TopicUtils::AsValidTopic(
"/" + this->dataPtr->robot_name + "/" + this->dataPtr->commandSubTopic
);
if (topic.empty())
{
gzerr << "Failed to create topic for command subscription." << std::endl;
return;
}
else
{
gzdbg << "Listening to topic: " << topic << std::endl;
}
this->dataPtr->node.Subscribe(topic,
&ReversibleMulticopterMotorModelPrivate::OnActuatorMsg, this->dataPtr.get());
}

void ReversibleMulticopterMotorModel::PreUpdate(const UpdateInfo &_info,
EntityComponentManager &_ecm)
{
GZ_PROFILE("ReversibleMulticopterMotorModel::PreUpdate");

if (_info.paused) {
return;
}

if (this->dataPtr->jointEntity == kNullEntity ||
this->dataPtr->linkEntity == kNullEntity) {
gzerr << "Joint or link entity is null." << std::endl;
return;
}

if (!_ecm.Component<components::JointVelocityCmd>(this->dataPtr->jointEntity))
{
_ecm.CreateComponent(this->dataPtr->jointEntity, components::JointVelocityCmd({0}));
}

this->dataPtr->UpdateForcesAndMoments(_ecm);
}

void ReversibleMulticopterMotorModelPrivate::OnActuatorMsg(
const msgs::Actuators &_msg)
{
std::lock_guard<std::mutex> lock(this->recvdActuatorsMsgMutex);
this->recvdActuatorsMsg = _msg;
}

void ReversibleMulticopterMotorModelPrivate::UpdateForcesAndMoments(
EntityComponentManager &_ecm)
{
GZ_PROFILE("ReversibleMulticopterMotorModelPrivate::UpdateForcesAndMoments");

auto actuatorMsgComp = _ecm.Component<components::Actuators>(this->model.Entity());
std::optional<msgs::Actuators> msg;

if (actuatorMsgComp)
{
msg = actuatorMsgComp->Data();
} else {
std::lock_guard<std::mutex> lock(this->recvdActuatorsMsgMutex);

if (this->recvdActuatorsMsg.has_value())
{
msg = *this->recvdActuatorsMsg;
this->recvdActuatorsMsg.reset();
}
}


if (msg.has_value()) {
if (msg->velocity_size() > this->motorNumber) {
this->motorInputVel = std::clamp(
msg->velocity(this->motorNumber),
-this->maxRotVelocity,
this->maxRotVelocity
);
} else if (msg->normalized_size() > this->motorNumber) {
this->motorInputVel = std::clamp(msg->normalized(this->motorNumber), -1.0, 1.0) * this->maxRotVelocity;
}
}

sim::Link link(this->linkEntity);
const auto worldPose = link.WorldPose(_ecm);
using Vector3 = math::Vector3d;

// Compute thrust according to the polynomial we have defined
double thrust = 0.0;
for (unsigned int i = 0; i < this->ThrustPolynomial.size(); i++) {
thrust += this->ThrustPolynomial[i] * std::pow(this->motorInputVel, i);
}

link.AddWorldForce(_ecm, worldPose->Rot().RotateVector(Vector3(0, 0, thrust)));

double torque = 0.0;

for (unsigned int i = 0; i < this->TorquePolynomial.size(); i++) {
torque += this->TorquePolynomial[i] * std::pow(this->motorInputVel, i);
}

link.AddWorldForce(_ecm, worldPose->Rot().RotateVector(Vector3(0, 0, torque)));

const auto jointVelCmd = _ecm.Component<components::JointVelocityCmd>(
this->jointEntity);
*jointVelCmd = components::JointVelocityCmd({this->motorInputVel / this->simVelSlowDown});
}

GZ_ADD_PLUGIN(ReversibleMulticopterMotorModel,
System,
ReversibleMulticopterMotorModel::ISystemConfigure,
ReversibleMulticopterMotorModel::ISystemPreUpdate)

GZ_ADD_PLUGIN_ALIAS(ReversibleMulticopterMotorModel,
"gz::sim::systems::ReversibleMulticopterMotorModel")
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifndef GZ_SIM_SYSTEMS_REVERSIBLEMULTICOPTERMOTORMODEL_HH_
#define GZ_SIM_SYSTEMS_REVERSIBLEMULTICOPTERMOTORMODEL_HH_

#include <gz/sim/System.hh>
#include <memory>

namespace gz
{
namespace sim
{
// Inline bracket to help doxygen filtering.
inline namespace GZ_SIM_VERSION_NAMESPACE {
namespace systems
{
// Forward declaration
// Using real world test with a reversible motor, we discovered the best way we had to simulate a reversible motor, was to use a third order model for both the thrust and the torque. This was done this way since the enviroment in which the real world robot would be used would have no wind. This also meant that we dont need to compute drag coeficients and rolling moment coeficients
// Please note that this pluggin is not supposed to be general but insteal used with the Space Cobot model, since we tested our motor in testbench and used the following results to create the model if you want to used this model, you will need to do this
// polynomails are in the type of a0 + a1*x + a2*x^2 + a3*x^3 = torque
class ReversibleMulticopterMotorModelPrivate;
/// \brief This system applies a thrust force to models with spinning
/// propellers, considering both normal and reverse motor directions.
class ReversibleMulticopterMotorModel
: public System,
public ISystemConfigure,
public ISystemPreUpdate
{
/// \brief Constructor
public: ReversibleMulticopterMotorModel();

/// \brief Destructor
public: ~ReversibleMulticopterMotorModel() override = default;

// Documentation inherited
public: void Configure(const Entity &_entity,
const std::shared_ptr<const sdf::Element> &_sdf,
EntityComponentManager &_ecm,
EventManager &_eventMgr) override;

// Documentation inherited
public: void PreUpdate(
const gz::sim::UpdateInfo &_info,
gz::sim::EntityComponentManager &_ecm) override;

/// \brief Private data pointer
private: std::unique_ptr<ReversibleMulticopterMotorModelPrivate> dataPtr;
};
}
}
}
}

#endif