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 a service to trigger functionality #1611

Merged
merged 28 commits into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2e83824
initial commit to allow plugin to call a service
liamhan0905 Jul 25, 2022
48a1a11
adding tutorial and modifying the world sdf
liamhan0905 Jul 25, 2022
8b1fb70
added test for single input and single service output
liamhan0905 Jul 26, 2022
3361e9a
added test for single input and multiple service output
liamhan0905 Jul 26, 2022
8209f6b
added test for invalid matching service name => timeout
liamhan0905 Jul 26, 2022
8cee834
modified variables the camelCase
liamhan0905 Jul 27, 2022
4d4d384
fixed typo, indentation, grammar, lines that exceeded 80 char
liamhan0905 Jul 28, 2022
55e1035
fixing ubuntu bionic ci issue
liamhan0905 Jul 28, 2022
e0f56ea
silly syntax mistake on expect_eq
liamhan0905 Jul 28, 2022
a220057
added three more test cases that addesses incorrect response type, in…
liamhan0905 Aug 1, 2022
cc4b665
WIP: major restructuring and currently working. Requires more cleanup…
liamhan0905 Aug 3, 2022
d5b016a
WIP: fixed preprocessor define bug
liamhan0905 Aug 3, 2022
a567385
WIP: working but extremely convoluted
liamhan0905 Aug 4, 2022
6aca06f
WIP major modification but a lot of errors and tests failed
liamhan0905 Aug 4, 2022
aa5090b
stable version: had to revert back to previous work. all tests passed
liamhan0905 Aug 4, 2022
759c7fd
modified to use blocking Request method as well as reduce a service w…
liamhan0905 Aug 8, 2022
8295ebb
stable version: had to revert back to previous work. all tests passed
liamhan0905 Aug 4, 2022
fe97579
rebasing
liamhan0905 Aug 8, 2022
10d946f
successfully reverted and tested
liamhan0905 Aug 8, 2022
a811126
fixing PR suggestions
liamhan0905 Aug 13, 2022
d64b17e
changed string with 'serv' to 'srv' and included <mutex> to the header
liamhan0905 Aug 23, 2022
33a2a73
fixed indentation and removed rep.set_data since it's unused on the c…
liamhan0905 Aug 30, 2022
7b5b33f
getting rid of the id
liamhan0905 Aug 30, 2022
d1ba98c
fixed race condition resulting seldom test failure
liamhan0905 Aug 31, 2022
0569e10
changed from triggerSrv to serviceCount. This compensates for the two…
liamhan0905 Aug 31, 2022
fced8fb
braces indentation
mabelzhang Sep 3, 2022
55e3e4d
Merge branch 'ign-gazebo6' into liam/add-serv-to-trig-pub
liamhan0905 Sep 6, 2022
a88d88e
addressing gnu c compiler (gcc) warnings
liamhan0905 Sep 7, 2022
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
35 changes: 30 additions & 5 deletions examples/worlds/triggered_publisher.sdf
Original file line number Diff line number Diff line change
Expand Up @@ -387,13 +387,17 @@ start falling.
<time>0.001</time>
<enabled>true</enabled>
</plugin>
<plugin filename="ignition-gazebo-detachable-joint-system" name="ignition::gazebo::systems::DetachableJoint">
<plugin
filename="ignition-gazebo-detachable-joint-system"
name="ignition::gazebo::systems::DetachableJoint">
<parent_link>body</parent_link>
<child_model>box1</child_model>
<child_link>box_body</child_link>
<topic>/box1/detach</topic>
</plugin>
<plugin filename="ignition-gazebo-detachable-joint-system" name="ignition::gazebo::systems::DetachableJoint">
<plugin
filename="ignition-gazebo-detachable-joint-system"
name="ignition::gazebo::systems::DetachableJoint">
<parent_link>body</parent_link>
<child_model>box2</child_model>
<child_link>box_body</child_link>
Expand Down Expand Up @@ -448,19 +452,40 @@ start falling.
</link>
</model>

<plugin filename="ignition-gazebo-triggered-publisher-system" name="ignition::gazebo::systems::TriggeredPublisher">
<plugin
filename="ignition-gazebo-triggered-publisher-system"
name="ignition::gazebo::systems::TriggeredPublisher">
<input type="ignition.msgs.Empty" topic="/start"/>
<output type="ignition.msgs.Twist" topic="/cmd_vel">
linear: {x: 3}
</output>
</plugin>
<plugin filename="ignition-gazebo-triggered-publisher-system" name="ignition::gazebo::systems::TriggeredPublisher">
<plugin
filename="ignition-gazebo-triggered-publisher-system"
name="ignition::gazebo::systems::TriggeredPublisher">
<input type="ignition.msgs.Empty" topic="/reset_robot"/>
<output type="ignition.msgs.Twist" topic="/cmd_vel">
linear: {x: 0}
</output>
<service
name="/world/triggered_publisher/set_pose"
reqType="ignition.msgs.Pose"
repType="ignition.msgs.Boolean"
timeout="3000"
reqMsg="name: 'blue_vehicle', position: {x: -3, z: 0.325}">
</service>
</plugin>
<plugin
filename="ignition-gazebo-triggered-publisher-system"
name="ignition::gazebo::systems::TriggeredPublisher">
<input type="ignition.msgs.Boolean" topic="/trigger/touched">
<match>data: true</match>
</input>
<output type="ignition.msgs.Empty" topic="/box1/detach"/>
</plugin>
<plugin filename="ignition-gazebo-triggered-publisher-system" name="ignition::gazebo::systems::TriggeredPublisher">
<plugin
filename="ignition-gazebo-triggered-publisher-system"
name="ignition::gazebo::systems::TriggeredPublisher">
<input type="ignition.msgs.Altimeter" topic="/altimeter">
<match field="vertical_position" tol="0.2">-7.5</match>
</input>
Expand Down
158 changes: 140 additions & 18 deletions src/systems/triggered_publisher/TriggeredPublisher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ FullMatcher::FullMatcher(const std::string &_msgType, bool _logicType,
: InputMatcher(_msgType), logicType(_logicType)
{
if (nullptr == this->matchMsg || !this->matchMsg->IsInitialized())
{
return;
}

this->valid = google::protobuf::TextFormat::ParseFromString(
_matchString, this->matchMsg.get());
Expand All @@ -273,7 +275,9 @@ FieldMatcher::FieldMatcher(const std::string &_msgType, bool _logicType,
fieldName(_fieldName)
{
if (nullptr == this->matchMsg || !this->matchMsg->IsInitialized())
{
return;
}

transport::ProtoMsg *matcherSubMsg{nullptr};
if (!FindFieldSubMessage(this->matchMsg.get(), _fieldName,
Expand All @@ -294,7 +298,9 @@ FieldMatcher::FieldMatcher(const std::string &_msgType, bool _logicType,
}

if (nullptr == matcherSubMsg)
{
return;
}

bool result = google::protobuf::TextFormat::ParseFieldValueFromString(
_fieldString, this->fieldDescMatcher.back(), matcherSubMsg);
Expand Down Expand Up @@ -548,7 +554,9 @@ void TriggeredPublisher::Configure(const Entity &,
{
int ms = sdfClone->Get<int>("delay_ms");
if (ms > 0)
{
this->delay = std::chrono::milliseconds(ms);
}
}

if (sdfClone->HasElement("output"))
Expand Down Expand Up @@ -595,9 +603,52 @@ void TriggeredPublisher::Configure(const Entity &,
}
}
}
else

if (sdfClone->HasElement("service"))
{
ignerr << "No ouptut specified" << std::endl;
for (auto serviceElem = sdfClone->GetElement("service"); serviceElem;
serviceElem = serviceElem->GetNextElement("service"))
{
SrvOutputInfo serviceInfo;
serviceInfo.srvName = serviceElem->Get<std::string>("name");
if (serviceInfo.srvName.empty())
{
ignerr << "Service name cannot be empty\n";
return;
}
serviceInfo.reqType = serviceElem->Get<std::string>("reqType");
if (serviceInfo.reqType.empty())
{
ignerr << "Service request type cannot be empty\n";
return;
}
serviceInfo.repType = serviceElem->Get<std::string>("repType");
if (serviceInfo.repType.empty())
{
ignerr << "Service reply type cannot be empty\n";
return;
}
serviceInfo.reqMsg = serviceElem->Get<std::string>("reqMsg");
if (serviceInfo.reqMsg.empty())
{
ignerr << "Service request message cannot be empty\n";
return;
}
std::string timeoutInfo = serviceElem->Get<std::string>("timeout");
if (timeoutInfo.empty())
{
ignerr << "Timeout value cannot be empty\n";
return;
}

serviceInfo.timeout = std::stoi(timeoutInfo);
this->srvOutputInfo.push_back(std::move(serviceInfo));
}
}
if (!sdfClone->HasElement("service") && !sdfClone->HasElement("output"))
{
ignerr << "No output and service specified. Make sure to specify at least"
"one of them." << std::endl;
return;
}

Expand All @@ -606,23 +657,27 @@ void TriggeredPublisher::Configure(const Entity &,
{
if (this->MatchInput(_msg))
{
if (this->delay > 0ms)
{
std::lock_guard<std::mutex> lock(this->publishQueueMutex);
this->publishQueue.push_back(this->delay);
}
else
{
if (this->delay > 0ms)
{
std::lock_guard<std::mutex> lock(this->publishQueueMutex);
this->publishQueue.push_back(this->delay);
}
else
{
{
std::lock_guard<std::mutex> lock(this->publishCountMutex);
++this->publishCount;
}
this->newMatchSignal.notify_one();
std::lock_guard<std::mutex> lock(this->publishCountMutex);
++this->publishCount;
}
this->newMatchSignal.notify_one();
}
if (this->srvOutputInfo.size() > 0)
{
std::lock_guard<std::mutex> lock(this->triggerSrvMutex);
++this->serviceCount;
}
}
});

if (!this->node.Subscribe(this->inputTopic, msgCb))
{
ignerr << "Input subscriber could not be created for topic ["
Expand All @@ -645,11 +700,69 @@ void TriggeredPublisher::Configure(const Entity &,
std::thread(std::bind(&TriggeredPublisher::DoWork, this));
}

//////////////////////////////////////////////////
void TriggeredPublisher::PublishMsg(std::size_t pending)
{
for (auto &info : this->outputInfo)
{
for (std::size_t i = 0; i < pending; ++i)
{
info.pub.Publish(*info.msgData);
}
}
}

//////////////////////////////////////////////////
void TriggeredPublisher::CallService(std::size_t pendingSrv)
{
for (auto &serviceInfo : this->srvOutputInfo)
{
for (std::size_t i = 0; i < pendingSrv; ++i)
{
bool result;
auto req = msgs::Factory::New(serviceInfo.reqType, serviceInfo.reqMsg);
if (!req)
{
ignerr << "Unable to create request for type ["
<< serviceInfo.reqType << "].\n";
return;
}

auto rep = msgs::Factory::New(serviceInfo.repType);
if (!rep)
{
ignerr << "Unable to create response for type ["
<< serviceInfo.repType << "].\n";
return;
}

bool executed = this->node.Request(serviceInfo.srvName, *req,
serviceInfo.timeout, *rep, result);
if (executed)
{
if (!result)
{
ignerr << "Service call [" << serviceInfo.srvName << "] failed\n";
}
else
{
ignmsg << "Service call [" << serviceInfo.srvName << "] succeeded\n";
}
}
else
{
ignerr << "Service call [" << serviceInfo.srvName << "] timed out\n";
}
}
}
}

//////////////////////////////////////////////////
void TriggeredPublisher::DoWork()
{
while (!this->done)
{
// check whether to publish a msg by checking publishCount
std::size_t pending{0};
{
using namespace std::chrono_literals;
Expand All @@ -661,18 +774,25 @@ void TriggeredPublisher::DoWork()
});

if (this->publishCount == 0 || this->done)
{
continue;

}
std::swap(pending, this->publishCount);
}

for (auto &info : this->outputInfo)
PublishMsg(pending);

// check whether to call a service by checking serviceCount
std::size_t pendingSrv{0};
{
for (std::size_t i = 0; i < pending; ++i)
{
info.pub.Publish(*info.msgData);
std::lock_guard<std::mutex> lock(this->triggerSrvMutex);
if (this->serviceCount == 0 || this->done){
continue;
}
std::swap(pendingSrv, this->serviceCount);
}

CallService(pendingSrv);
}
}

Expand Down Expand Up @@ -712,7 +832,9 @@ void TriggeredPublisher::PreUpdate(const ignition::gazebo::UpdateInfo &_info,
}

if (notify)
{
this->newMatchSignal.notify_one();
}
}

//////////////////////////////////////////////////
Expand Down
Loading