Bridge Between Domains

10 posts / 0 new
Last post
Offline
Last seen: 10 months 1 day ago
Joined: 06/24/2021
Posts: 9
Bridge Between Domains

I'm trying to build a generic bridge between two domains, it needs to be "generic" in the sense it can't use IDL and needs to find topics at run time on one domain and then republish them on a second domain.

 

I've googled (found examples that don't help and some don't even compile) and looked at the routing service but it comes with too much baggage. I've tried creating a solution by cutting and pasting from different slices of code I've found, but it's turned into a bit of a Frankenstien Monster.

 

I think I should be able to get dynamic data and dynamic type to subscribe and then publish the data. I've seen examples of reading dynamic data, I've seen examples creating a dynamic data publisher, but I'd like to be able push the subscribed data straight through to the publisher.

 

I'm working in modern C++.

 

Can someone either poinr me an example or provide simple code that does the following ...

 

Using the builtin objects, find all topics being published and read their messages.

From the messages build a dynamic data publisher (with a different domain id)

Drop the type and data from the subscribed topic into the publisher and publish data.

 

Any push in the right direction greatly recieved,

Howard's picture
Offline
Last seen: 1 day 2 hours ago
Joined: 11/29/2012
Posts: 565

Not sure what you mean by "too much baggage"...but what you're trying to do is one of the fundamental use cases supported by Routing Service.

Offline
Last seen: 10 months 1 day ago
Joined: 06/24/2021
Posts: 9

It's the plugins, all the command line arguments, the message transformation, the ability to talk protocols other than DDS - all very handy if you want to use the Routing Service as supplied, but makes it difficult to find the simpliest way to do one thing.

Howard's picture
Offline
Last seen: 1 day 2 hours ago
Joined: 11/29/2012
Posts: 565

?

If you run RoutingService using the RTI Launcher (which gives you the command line arguments) and select the default configuration from the example XML configuration file provided, it will do exactly what you exactly what you want it to do, subscribe to topics in one domain and republish it in another domain.

But if you find learning Routing Service too difficult...I guess you'll have to figure out how to do it with the Dynamic Data API, which is what Routing Service uses internally.

Offline
Last seen: 10 months 1 day ago
Joined: 06/24/2021
Posts: 9

Sorry, I've been a bit flippant in my request for help.

I the Routing Service has far more features than I need - I'm looking a "lean" solution - just needs to be able to republish to a different domain.

I've been researching DynamicData, and been able to build a subscriber that identifies all topics found on the DDS bus, and retrieve the associated info and data.

Separately I've seen how to create a DynamicData publisher that can be feed IDL or XML or can construct the topic type from code. What I can't see how to do is use the info and data from the subscribed topic to create a Publisher and then publish that data.

I can show the code I have so far, but it's really ratty after a couple of weeks of cutting and pasting code snippets trying to get a working solution.

Howard's picture
Offline
Last seen: 1 day 2 hours ago
Joined: 11/29/2012
Posts: 565

Once you get the PublicationBuiltinTopicData or SubscriptionBuiltinTopicData with your "subscriber" that identifies all topics found on the DDS bus, you use the "type_code" member in either structure to create DynamicData objects which are generic objects that can hold data for any data type, but when you create one with a type_code, you have

I assume you've seen this documentation:

https://community.rti.com/static/documentation/connext-dds/6.1.2/doc/api/connext_dds/api_cpp2/group__DDSXTypesExampleModule.html#DDSXTypesExampleModule_dynamic_type_creation_xml

So, from the DynamicType object that you get from the "type_code" member, you need to register the type with the DomainParticipant using register_type,

And then off you go.  You need to create a topic with the registered type and a DataWriter<DynamicData> with the topic.

Offline
Last seen: 10 months 1 day ago
Joined: 06/24/2021
Posts: 9

I'm almost there, I went back to the begining and stripped down the "using_type_codes" example and merged the publish into the subscribe while transitioning to DynamicData and have this ...

#include <dds/sub/ddssub.hpp>
#include <dds/core/ddscore.hpp>
#include <rti/config/Logger.hpp> // for logging
int domain_id = 0;int process_data(dds::sub::DataReader<dds::topic::PublicationBuiltinTopicData> reader)
{
int count = 0;
dds::sub::LoanedSamples<dds::topic::PublicationBuiltinTopicData> samples = reader.take();for (const auto &sample : samples)
{
if (sample.info().valid())
{
const dds::topic::PublicationBuiltinTopicData &data = sample.data();
std::string topic_name = data.topic_name().to_std_string();
dds::core::optional<dds::core::xtypes::DynamicType> topic_type = data->type();
std::string topic_type_name = data.type_name().to_std_string();
std::cout << "topic:" << data.topic_name() << std::endl
<< "type:" << std::endl;
if (!data->type().is_set())
{
std::cout << "No type received" << std::endl;
}
else
{
rti::core::xtypes::print_idl(data->type().get(), 2);
std::cout << std::endl;
// now publish on the "other" domain
dds::domain::DomainParticipant participant(domain_id + 1);
rti::domain::register_type(participant, topic_type_name, topic_type);
dds::topic::Topic<dds::core::xtypes::DynamicData> topic(participant, topic_name, topic_type);
dds::pub::Publisher publisher(participant);
dds::pub::DataWriter<dds::core::xtypes::DynamicData> writer(publisher, topic);
writer.write(data);
count++;
}
}
}
return count;
}
int main(int argc, char *argv[])
{
// rti::config::Logger::instance().verbosity(rti::config::Verbosity::STATUS_LOCAL);
rti::config::Logger::instance().verbosity(rti::config::Verbosity::EXCEPTION);
dds::domain::qos::DomainParticipantQos participant_qos = dds::core::QosProvider::Default()->participant_qos();dds::domain::DomainParticipant participant(domain_id, participant_qos);dds::sub::Subscriber builtin_subscriber = dds::sub::builtin_subscriber(participant);dds::sub::DataReader<dds::topic::PublicationBuiltinTopicData>
publication_reader = rti::sub::find_datareader_by_topic_name<
dds::sub::DataReader<
dds::topic::PublicationBuiltinTopicData>>(
builtin_subscriber,
dds::topic::publication_topic_name());
dds::core::cond::WaitSet waitset;unsigned int samples_read = 0;dds::sub::cond::ReadCondition read_condition(
publication_reader,
dds::sub::status::DataState::any(),
[publication_reader, &samples_read]()
{
samples_read += process_data(publication_reader);
});
waitset += read_condition;while (1)
{
waitset.dispatch(dds::core::Duration(1));
}
}

 

I've got three compile errors ...

bridge.cxx:38:84: error: no matching function for call to ‘register_type(dds::domain::DomainParticipant&, std::string&, rti::core::optional<rti::core::xtypes::DynamicTypeImpl>&)’

bridge.cxx:40:108: error: no matching function for call to ‘dds::topic::Topic<rti::core::xtypes::DynamicDataImpl>::Topic(dds::domain::DomainParticipant&, std::string&, rti::core::optional<rti::core::xtypes::DynamicTypeImpl>&)’

bridge.cxx:44:77: error: variable ‘dds::pub::DataWriter<rti::core::xtypes::DynamicDataImpl> writer’ has initializer but incomplete type

 

... clearly a problem with the Dynamic Data/Type definitions, but I can't pick it.

 

Howard's picture
Offline
Last seen: 1 day 2 hours ago
Joined: 11/29/2012
Posts: 565

You need to access the dynamic type object using: data->type().get()

e.g.

rti::domain::register_type(participant, topic_type_name, topic_type.get());

 

Offline
Last seen: 10 months 1 day ago
Joined: 06/24/2021
Posts: 9

Hopefully the last problem, what belongs in the last parameter of this constructor ...

dds::topic::Topic<dds::core::xtypes::DynamicData> topic(participant, topic_name, topic_type);

...

bridge.cxx:40:108: error: no matching function for call to ‘dds::topic::Topic<rti::core::xtypes::DynamicDataImpl>::Topic(dds::domain::DomainParticipant&, std::string&, const rti::core::optional<rti::core::xtypes::DynamicTypeImpl>&)’

40 | dds::topic::Topic<dds::core::xtypes::DynamicData> topic(participant, topic_name, topic_type);

 

I thought it was supposed to be the type_code I was able to retrieve earlier.

Howard's picture
Offline
Last seen: 1 day 2 hours ago
Joined: 11/29/2012
Posts: 565

The documentation for the constructor of the Topic shows:

https://community.rti.com/static/documentation/connext-dds/6.1.2/doc/api/connext_dds/api_cpp2/classdds_1_1topic_1_1Topic.html#a8bdc62fcdcb95aa55dd8c980e6293035

template<typename T>
dds::topic::Topic< T >::Topic(const dds::domain::DomainParticipantthe_participant,
  const std::string & topic_name,
  const dds::core::xtypes::DynamicTypetype 
 ) 

 

but dds::topic::PublicationBuiltinTopicData::type()

returns an object of type "dds::core::optional<dds::core::xtypes::DynamicType> "

which provides a get() method to get the underlying object of type dds::core::xtypes::DynamicType

so you need to use (as in register_type());

dds::topic::Topic<dds::core::xtypes::DynamicData> topic(participant, topic_name, topic_type.get());