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

Add wheel slip user command #1241

Merged
merged 42 commits into from Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3466e40
Add wheel slip command
ivanpauno Dec 3, 2021
c3b422f
Handle WheelSlipCmd
ivanpauno Dec 6, 2021
df40169
Use validWorldName instead of worldName in topics
ivanpauno Jan 3, 2022
e9220f1
linters
ivanpauno Jan 4, 2022
a103075
more linters
ivanpauno Jan 4, 2022
7c2b087
msgs::WheelSlip -> msgs::WheelSlipParameters
ivanpauno Jan 4, 2022
40949e2
Address peer review comment
ivanpauno Jan 12, 2022
979676d
style
ivanpauno Feb 2, 2022
401352e
style
ivanpauno Feb 2, 2022
530c8ae
Make it work
ivanpauno Feb 4, 2022
866bd93
Remove debugging messages
ivanpauno Feb 4, 2022
8a9c754
linters
ivanpauno Feb 4, 2022
b5d739e
Add `link_name: '*'` option.
ivanpauno Mar 1, 2022
cc6295a
Please linters
ivanpauno Mar 4, 2022
4377757
add minimal test case
ivanpauno Mar 4, 2022
8ea472f
Use msgs::Entity instead of model_name/link_name
ivanpauno Mar 11, 2022
75ad4fb
copyright notice year: 2021 -> 2022
ivanpauno Mar 15, 2022
cfb6020
Make codecheck pass
ivanpauno Mar 15, 2022
b1ea7eb
Update include
ivanpauno Mar 21, 2022
f248c12
Add wheel slip command
ivanpauno Dec 3, 2021
6a6c400
Handle WheelSlipCmd
ivanpauno Dec 6, 2021
0b73268
Use validWorldName instead of worldName in topics
ivanpauno Jan 3, 2022
1e7952c
linters
ivanpauno Jan 4, 2022
12713aa
more linters
ivanpauno Jan 4, 2022
5db5559
msgs::WheelSlip -> msgs::WheelSlipParameters
ivanpauno Jan 4, 2022
d62a6b2
Address peer review comment
ivanpauno Jan 12, 2022
96ce1a1
style
ivanpauno Feb 2, 2022
84ab290
style
ivanpauno Feb 2, 2022
8c00e8c
Make it work
ivanpauno Feb 4, 2022
480bd5c
Remove debugging messages
ivanpauno Feb 4, 2022
185c8e8
linters
ivanpauno Feb 4, 2022
dc17dae
Add `link_name: '*'` option.
ivanpauno Mar 1, 2022
a82ef55
Please linters
ivanpauno Mar 4, 2022
18fa1e6
add minimal test case
ivanpauno Mar 4, 2022
bcab77b
Use msgs::Entity instead of model_name/link_name
ivanpauno Mar 11, 2022
c7b6db6
copyright notice year: 2021 -> 2022
ivanpauno Mar 15, 2022
def1f85
Make codecheck pass
ivanpauno Mar 15, 2022
05b8869
Update include
ivanpauno Mar 21, 2022
77b76ab
Merge branch 'ivanpauno/wheel-slip-cmd' of https://github.com/ignitio…
ivanpauno Mar 21, 2022
f9161d3
Maybe fix CI issue
ivanpauno Mar 23, 2022
19606cd
Do what the other tests are doing: skip on windows
ivanpauno Mar 23, 2022
5f92368
Merge branch 'ign-gazebo5' into ivanpauno/wheel-slip-cmd
ivanpauno Mar 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 46 additions & 0 deletions include/ignition/gazebo/components/WheelSlipCmd.hh
@@ -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>
Comment on lines +20 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alphabetize

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, you mean like

Suggested change
#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/gazebo/components/Component.hh>
#include <ignition/gazebo/components/Factory.hh>
#include <ignition/gazebo/components/Serialization.hh>
#include <ignition/gazebo/config.hh>
#include <ignition/gazebo/Export.hh>

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 are config.hh, Export.hh), after that I put the subfolders in alpha order (only components 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 after Z), or if I should ignore casing when ordering.
In the first case it should be:

Suggested change
#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/gazebo/Export.hh>
#include <ignition/gazebo/components/Component.hh>
#include <ignition/gazebo/components/Factory.hh>
#include <ignition/gazebo/components/Serialization.hh>
#include <ignition/gazebo/config.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
211 changes: 211 additions & 0 deletions src/systems/user_commands/UserCommands.cc
Expand Up @@ -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>
Expand All @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}};
};
}
}
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Copy link
Contributor

Choose a reason for hiding this comment

The 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 LIGHT, instead of LINK. If so, we can just throw an error at the very start saying that WheelSlip command msg is only meant for links, and we can avoid checking all these cases.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WheelSlip msg is meant for links or models.
The second is used similarly to what before was the link_name == '*' option for.

I think that the idea is to reuse the same Entity msg everywhere, based on the feedback I got in gazebosim/gz-msgs#227 (comment).

You can also use type == NONE (i.e. not specified), and only pass a name.

<< "], 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
Expand Down
30 changes: 28 additions & 2 deletions src/systems/wheel_slip/WheelSlip.cc
Expand Up @@ -33,6 +33,7 @@
#include "ignition/gazebo/components/Joint.hh"
#include "ignition/gazebo/components/JointVelocity.hh"
#include "ignition/gazebo/components/SlipComplianceCmd.hh"
#include "ignition/gazebo/components/WheelSlipCmd.hh"

using namespace ignition;
using namespace gazebo;
Expand Down Expand Up @@ -107,7 +108,9 @@ class ignition::gazebo::systems::WheelSlipPrivate
{
if (_a.size() != _b.size() ||
_a.size() < 2 ||_b.size() < 2)
{
return false;
}

for (size_t i = 0; i < _a.size(); i++)
{
Expand Down Expand Up @@ -242,9 +245,32 @@ bool WheelSlipPrivate::Load(const EntityComponentManager &_ecm,
/////////////////////////////////////////////////
void WheelSlipPrivate::Update(EntityComponentManager &_ecm)
{
for (const auto &linkSurface : this->mapLinkSurfaceParams)
for (auto &linkSurface : this->mapLinkSurfaceParams)
{
const auto &params = linkSurface.second;
auto &params = linkSurface.second;
const auto * wheelSlipCmdComp =
_ecm.Component<components::WheelSlipCmd>(linkSurface.first);
if (wheelSlipCmdComp)
{
const auto & wheelSlipCmdParams = wheelSlipCmdComp->Data();
bool changed = (!math::equal(
params.slipComplianceLateral,
wheelSlipCmdParams.slip_compliance_lateral(),
1e-6)) ||
(!math::equal(
params.slipComplianceLongitudinal,
wheelSlipCmdParams.slip_compliance_longitudinal(),
1e-6));

if (changed)
{
params.slipComplianceLateral =
wheelSlipCmdParams.slip_compliance_lateral();
params.slipComplianceLongitudinal =
wheelSlipCmdParams.slip_compliance_longitudinal();
}
_ecm.RemoveComponent<components::WheelSlipCmd>(linkSurface.first);
}

// get user-defined normal force constant
double force = params.wheelNormalForce;
Expand Down