-
Notifications
You must be signed in to change notification settings - Fork 277
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
Add wheel slip user command #1241
Changes from 18 commits
3466e40
c3b422f
df40169
e9220f1
a103075
7c2b087
40949e2
979676d
401352e
530c8ae
866bd93
8a9c754
b5d739e
cc6295a
4377757
8ea472f
75ad4fb
cfb6020
b1ea7eb
f248c12
6a6c400
0b73268
1e7952c
12713aa
5db5559
d62a6b2
96ce1a1
84ab290
8c00e8c
480bd5c
185c8e8
dc17dae
a82ef55
18fa1e6
bcab77b
c7b6db6
def1f85
05b8869
77b76ab
f9161d3
19606cd
5f92368
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Copyright (C) 2022 Open Source Robotics Foundation | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
#ifndef IGNITION_GAZEBO_COMPONENTS_WHEELSLIPCMD_HH_ | ||
#define IGNITION_GAZEBO_COMPONENTS_WHEELSLIPCMD_HH_ | ||
|
||
#include <ignition/gazebo/config.hh> | ||
#include <ignition/gazebo/Export.hh> | ||
#include <ignition/gazebo/components/Component.hh> | ||
#include <ignition/gazebo/components/Factory.hh> | ||
#include <ignition/gazebo/components/Serialization.hh> | ||
|
||
#include <ignition/msgs/wheel_slip_parameters_cmd.pb.h> | ||
|
||
namespace ignition | ||
{ | ||
namespace gazebo | ||
{ | ||
// Inline bracket to help doxygen filtering. | ||
inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE { | ||
namespace components | ||
{ | ||
/// \brief A component type that contains commanded wheel slip parameters of | ||
/// an entity in the world frame represented by msgs::WheelSlipParameters. | ||
using WheelSlipCmd = Component<ignition::msgs::WheelSlipParametersCmd, | ||
class WheelSlipCmdTag, serializers::MsgSerializer>; | ||
IGN_GAZEBO_REGISTER_COMPONENT("ign_gazebo_components.WheelSlipCmd", | ||
WheelSlipCmd) | ||
} | ||
} | ||
} | ||
} | ||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,9 +24,11 @@ | |
#include <ignition/msgs/pose.pb.h> | ||
#include <ignition/msgs/physics.pb.h> | ||
#include <ignition/msgs/visual.pb.h> | ||
#include <ignition/msgs/wheel_slip_parameters.pb.h> | ||
ivanpauno marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
#include <string> | ||
#include <utility> | ||
#include <unordered_set> | ||
#include <vector> | ||
|
||
#include <ignition/msgs/Utility.hh> | ||
|
@@ -41,6 +43,8 @@ | |
|
||
#include "ignition/common/Profiler.hh" | ||
|
||
#include "ignition/gazebo/components/Collision.hh" | ||
#include "ignition/gazebo/components/Joint.hh" | ||
#include "ignition/gazebo/components/Light.hh" | ||
#include "ignition/gazebo/components/LightCmd.hh" | ||
#include "ignition/gazebo/components/Link.hh" | ||
|
@@ -50,14 +54,18 @@ | |
#include "ignition/gazebo/components/Pose.hh" | ||
#include "ignition/gazebo/components/PoseCmd.hh" | ||
#include "ignition/gazebo/components/PhysicsCmd.hh" | ||
#include "ignition/gazebo/components/Visual.hh" | ||
#include "ignition/gazebo/components/World.hh" | ||
#include "ignition/gazebo/Conversions.hh" | ||
#include "ignition/gazebo/EntityComponentManager.hh" | ||
#include "ignition/gazebo/Model.hh" | ||
#include "ignition/gazebo/SdfEntityCreator.hh" | ||
#include "ignition/gazebo/Util.hh" | ||
#include "ignition/gazebo/components/ContactSensorData.hh" | ||
#include "ignition/gazebo/components/ContactSensor.hh" | ||
#include "ignition/gazebo/components/Sensor.hh" | ||
#include "ignition/gazebo/components/VisualCmd.hh" | ||
#include "ignition/gazebo/components/WheelSlipCmd.hh" | ||
|
||
using namespace ignition; | ||
using namespace gazebo; | ||
|
@@ -352,6 +360,48 @@ class VisualCommand : public UserCommandBase | |
aMaterial.emissive().a(), bMaterial.emissive().a(), 1e-6f); | ||
}}; | ||
}; | ||
|
||
/// \brief Command to modify a wheel entity from simulation. | ||
class WheelSlipCommand : public UserCommandBase | ||
{ | ||
/// \brief Constructor | ||
/// \param[in] _msg Message containing the wheel slip parameters. | ||
/// \param[in] _iface Pointer to user commands interface. | ||
public: WheelSlipCommand(msgs::WheelSlipParametersCmd *_msg, | ||
std::shared_ptr<UserCommandsInterface> &_iface); | ||
|
||
// Documentation inherited | ||
public: bool Execute() final; | ||
|
||
/// \brief WheelSlip equality comparision function | ||
public: std::function<bool( | ||
const msgs::WheelSlipParametersCmd &, const msgs::WheelSlipParametersCmd &)> | ||
wheelSlipEql { | ||
[]( | ||
const msgs::WheelSlipParametersCmd &_a, | ||
const msgs::WheelSlipParametersCmd &_b) | ||
{ | ||
return | ||
( | ||
( | ||
_a.entity().id() != kNullEntity && | ||
_a.entity().id() == _b.entity().id() | ||
) || | ||
( | ||
_a.entity().name() == _b.entity().name() && | ||
_a.entity().type() == _b.entity().type() | ||
) | ||
adityapande-1995 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) && | ||
math::equal( | ||
_a.slip_compliance_lateral(), | ||
_b.slip_compliance_lateral(), | ||
1e-6) && | ||
math::equal( | ||
_a.slip_compliance_longitudinal(), | ||
_b.slip_compliance_longitudinal(), | ||
1e-6); | ||
}}; | ||
}; | ||
} | ||
} | ||
} | ||
|
@@ -428,6 +478,16 @@ class ignition::gazebo::systems::UserCommandsPrivate | |
/// \return True if successful. | ||
public: bool VisualService(const msgs::Visual &_req, msgs::Boolean &_res); | ||
|
||
/// \brief Callback for wheel slip service | ||
/// \param[in] _req Request containing wheel slip parameter updates of an | ||
/// entity. | ||
/// \param[out] _res True if message sucessfully received and queued. | ||
/// It does not mean that the wheel slip parameters will be successfully | ||
/// updated. | ||
/// \return True if successful. | ||
public: bool WheelSlipService( | ||
const msgs::WheelSlipParametersCmd &_req, msgs::Boolean &_res); | ||
|
||
/// \brief Queue of commands pending execution. | ||
public: std::vector<std::unique_ptr<UserCommandBase>> pendingCmds; | ||
|
||
|
@@ -574,6 +634,14 @@ void UserCommands::Configure(const Entity &_entity, | |
&UserCommandsPrivate::VisualService, this->dataPtr.get()); | ||
|
||
ignmsg << "Material service on [" << visualService << "]" << std::endl; | ||
|
||
// Wheel slip service | ||
std::string wheelSlipService | ||
{"/world/" + validWorldName + "/wheel_slip"}; | ||
this->dataPtr->node.Advertise(wheelSlipService, | ||
&UserCommandsPrivate::WheelSlipService, this->dataPtr.get()); | ||
|
||
ignmsg << "Material service on [" << wheelSlipService << "]" << std::endl; | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
|
@@ -778,6 +846,25 @@ bool UserCommandsPrivate::VisualService(const msgs::Visual &_req, | |
return true; | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
bool UserCommandsPrivate::WheelSlipService( | ||
const msgs::WheelSlipParametersCmd &_req, | ||
msgs::Boolean &_res) | ||
{ | ||
// Create command and push it to queue | ||
auto msg = _req.New(); | ||
msg->CopyFrom(_req); | ||
auto cmd = std::make_unique<WheelSlipCommand>(msg, this->iface); | ||
// Push to pending | ||
{ | ||
std::lock_guard<std::mutex> lock(this->pendingMutex); | ||
this->pendingCmds.push_back(std::move(cmd)); | ||
} | ||
|
||
_res.set_data(true); | ||
return true; | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
UserCommandBase::UserCommandBase(google::protobuf::Message *_msg, | ||
std::shared_ptr<UserCommandsInterface> &_iface) | ||
|
@@ -1387,6 +1474,130 @@ bool VisualCommand::Execute() | |
return true; | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
WheelSlipCommand::WheelSlipCommand(msgs::WheelSlipParametersCmd *_msg, | ||
std::shared_ptr<UserCommandsInterface> &_iface) | ||
: UserCommandBase(_msg, _iface) | ||
{ | ||
} | ||
|
||
// TODO(ivanpauno): Move this somewhere else | ||
Entity scopedEntityFromMsg( | ||
const msgs::Entity & _msg, const EntityComponentManager & _ecm) | ||
{ | ||
if (_msg.id() != kNullEntity) { | ||
return _msg.id(); | ||
} | ||
std::unordered_set<Entity> entities = entitiesFromScopedName( | ||
_msg.name(), _ecm); | ||
if (entities.empty()) { | ||
ignerr << "Failed to find entity with scoped name [" << _msg.name() | ||
<< "]." << std::endl; | ||
return kNullEntity; | ||
} | ||
if (_msg.type() == msgs::Entity::NONE) { | ||
return *entities.begin(); | ||
} | ||
const components::BaseComponent * component; | ||
std::string componentType; | ||
for (const auto entity : entities) { | ||
switch (_msg.type()) { | ||
case msgs::Entity::LIGHT: | ||
component = _ecm.Component<components::Light>(entity); | ||
componentType = "LIGHT"; | ||
break; | ||
case msgs::Entity::MODEL: | ||
component = _ecm.Component<components::Model>(entity); | ||
componentType = "MODEL"; | ||
break; | ||
case msgs::Entity::LINK: | ||
component = _ecm.Component<components::Link>(entity); | ||
componentType = "LINK"; | ||
break; | ||
case msgs::Entity::VISUAL: | ||
component = _ecm.Component<components::Visual>(entity); | ||
componentType = "VISUAL"; | ||
break; | ||
case msgs::Entity::COLLISION: | ||
component = _ecm.Component<components::Collision>(entity); | ||
componentType = "COLLISION"; | ||
break; | ||
case msgs::Entity::SENSOR: | ||
component = _ecm.Component<components::Sensor>(entity); | ||
componentType = "SENSOR"; | ||
break; | ||
case msgs::Entity::JOINT: | ||
component = _ecm.Component<components::Joint>(entity); | ||
componentType = "JOINT"; | ||
break; | ||
default: | ||
componentType = "unknown"; | ||
break; | ||
} | ||
if (component != nullptr) { | ||
return entity; | ||
} | ||
} | ||
ignerr << "Found entity with scoped name [" << _msg.name() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, this error is thrown when a user requests a change in wheelslip value of say a link (wheel) but actually enters Entity as say There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WheelSlip msg is meant for links or models. I think that the idea is to reuse the same You can also use |
||
<< "], but it doesn't have a component of the required type [" | ||
<< componentType << "]." << std::endl; | ||
return kNullEntity; | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
bool WheelSlipCommand::Execute() | ||
{ | ||
auto wheelSlipMsg = dynamic_cast<const msgs::WheelSlipParametersCmd *>( | ||
this->msg); | ||
if (nullptr == wheelSlipMsg) | ||
{ | ||
ignerr << "Internal error, null wheel slip message" << std::endl; | ||
return false; | ||
} | ||
const auto & ecm = *this->iface->ecm; | ||
Entity entity = scopedEntityFromMsg(wheelSlipMsg->entity(), ecm); | ||
if (kNullEntity == entity) | ||
{ | ||
return false; | ||
} | ||
|
||
auto doForEachLink = [this, wheelSlipMsg](Entity linkEntity) { | ||
auto wheelSlipCmdComp = | ||
this->iface->ecm->Component<components::WheelSlipCmd>(linkEntity); | ||
if (!wheelSlipCmdComp) | ||
{ | ||
this->iface->ecm->CreateComponent( | ||
linkEntity, components::WheelSlipCmd(*wheelSlipMsg)); | ||
} | ||
else | ||
{ | ||
auto state = wheelSlipCmdComp->SetData( | ||
*wheelSlipMsg, this->wheelSlipEql) ? ComponentState::OneTimeChange | ||
: ComponentState::NoChange; | ||
this->iface->ecm->SetChanged( | ||
linkEntity, components::WheelSlipCmd::typeId, state); | ||
} | ||
}; | ||
const components::BaseComponent * component = | ||
ecm.Component<components::Link>(entity); | ||
|
||
if (nullptr != component) { | ||
doForEachLink(entity); | ||
return true; | ||
} | ||
component = ecm.Component<components::Model>(entity); | ||
if (nullptr != component) { | ||
Model model{entity}; | ||
for (const auto & linkEntity : model.Links(*this->iface->ecm)) { | ||
doForEachLink(linkEntity); | ||
} | ||
return true; | ||
} | ||
ignerr << "Found entity with scoped name [" << wheelSlipMsg->entity().name() | ||
<< "], is neither a model or a link." << std::endl; | ||
return false; | ||
} | ||
|
||
IGNITION_ADD_PLUGIN(UserCommands, System, | ||
UserCommands::ISystemConfigure, | ||
UserCommands::ISystemPreUpdate | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alphabetize
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, you mean like
When having nested folders, I group items in each subfolder and I only alphaorder each group.
i.e. I put first all header files in the parent folder (in alpha order, in this case the items in
ignition/gazebo
areconfig.hh
,Export.hh
), after that I put the subfolders in alpha order (onlycomponents
here) and the items of the subfolder in alpha order as well (i.e.Component.hh
,Factory.hh
,Serialization.hh
).I'm also not sure if lowercase letters are ordered after uppercase letters (like ascii code ordering,
a
goes afterZ
), or if I should ignore casing when ordering.In the first case it should be: