【问题标题】:Subscribing to the built-in topic "DCPSTopic" in DDS订阅 DDS 内置主题“DCPSTopic”
【发布时间】:2013-02-24 01:40:30
【问题描述】:

我正在尝试创建最简单的 C# 应用程序,它允许我获取所选 DDS 域中当前可用的主题。但我似乎无法让它工作。

// Create the DDS Domain participant on domain ID 0
DDS.DomainParticipant participant =                          
             DDS.DomainParticipantFactory.get_instance().create_participant(
                    0,
                    DDS.DomainParticipantFactory.PARTICIPANT_QOS_DEFAULT,
                    null, /* Listener */
                    DDS.StatusMask.STATUS_MASK_NONE);
DDS.Subscriber sub = participant.get_builtin_subscriber();
DDS.DataReader reader1 = sub.lookup_datareader("DCPSTopic");
DDS.TopicBuiltinTopicDataDataReader builtinReader1 =  
                       (DDS.TopicBuiltinTopicDataDataReader)reader1;
DDS.TopicBuiltinTopicDataSeq topicSeq = new DDS.TopicBuiltinTopicDataSeq(10) ;
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
builtinReader1.read(topicSeq, 
                    infoSeq, 
                    10, 
                    DDS.SampleStateKind.ANY_SAMPLE_STATE, 
                    DDS.ViewStateKind.ANY_VIEW_STATE,
                    DDS.InstanceStateKind.ANY_INSTANCE_STATE);

运行上面的代码时,我在最后一行 (builtinReader1.read(...)) 中收到“Retcode_NoData”异常,即使发布者和订阅者都在同一个域(域 0)中运行和发布。你知道我的代码有什么问题吗?

顺便说一句。我使用 DDS 的 RTI Connext 5.0 实现。

问候 约翰

【问题讨论】:

    标签: c# data-distribution-service


    【解决方案1】:

    使用 RTI Connext,TopicBuiltinTopic 的行为与预期不同。查看C# API DDS::TopicBuiltinTopicData Class Reference的文档:

    注意:DDS_TopicBuiltinTopicData 内置主题旨在传达 有关已发现主题的信息。本主题的样本不是 在线路上的单独数据包中传播。而是发送数据 作为其他内置主题携带的信息的一部分 (DDS::PublicationBuiltinTopicDataDDS::SubscriptionBuiltinTopicData)。因此TopicBuiltinTopicData DataReader 不会收到任何数据。

    它的基本意思是:由于 Connext 中实现发现的方式,您不会在任何TopicBuiltinTopicData DataReaders 中看到任何数据。这就是您在代码 sn-p 中观察到的内容。

    幸运的是,仍然可以在公共汽车上获取有关 Topics 的信息。这必须通过 PublicationBuiltinTopicData 和 SubscriptionBuiltinTopicData 进行。如果查看C# API DDS::PublicationBuiltinTopicData Class Reference 的文档,可以看到数据包含字符串字段topic_nametype_name。此外,您可以获得有关类型结构的信息,但这是更高级和特定于实现的信息。


    如果您打算实现对内置主题的发布和订阅的阅读,请注意三点。首先,不要像 "DCPSTopic" 那样硬编码内置主题的名称,而是参考相应的 TypeSupport 属性,如下所示:

    reader = sub.lookup_datareader(
                 DDS.PublicationBuiltinTopicDataTypeSupport.PUBLICATION_TOPIC_NAME);
    

    那么很高兴知道,使用 Connext,内置 DataReader 将不包含任何关于与内置订阅者位于同一 DomainParticipant 中的发布或订阅的示例。换句话说,您只能看到其他参与者的实体,而不能看到您自己的。

    最后,在玩弄你的代码时,我注意到样本的读取不起作用,除非我按如下方式替换序列的构造函数调用:

    DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();
    

    代替

    DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
    

    和数据序列类似。我不知道为什么会这样,但它应该没有任何实际意义。

    【讨论】:

    • 嗨 Reinier,感谢您的反馈!我已经实施了您的 3 条建议,并且现在也在使用内置主题/数据阅读器的订阅和发布。但是我的应用程序仍然没有给出任何反馈(“Retcode_NoData”异常除外)。我在运行其他 DDS 应用程序的笔记本电脑上运行该应用程序,所有这些都在域 0 上,但它们没有显示在我的应用程序中。您对可能出现的问题有任何其他建议吗?再次感谢!约翰
    • 您在笔记本电脑上运行rtiddsspy 工具时看到什么了吗?它应该发现总线上的所有 DataReader 和 DataWriters 并打印它们的主题和所有更新(默认)。如果确实没有显示任何结果,则说明您的笔记本电脑的设置有问题。如果它确实显示了结果,请您查看code snippet 看看是否适合您?为了调试它,我将只从您的笔记本电脑开始,并结合 RTI 的 Shapes 演示运行 sn-p。
    • 我尝试运行你的代码sn-p 而不是我的,你的工作就像它应该做的那样:) 内置的 TopicReader 没有给出任何结果,但可以(如你所说)阅读来自发布者/订阅者的主题。非常感谢您的帮助!
    【解决方案2】:

    雷尼尔是对的。 Connext DDS 不会直接在TopicBuiltinTopicData 中传播主题;而是在PublicationBuitinTopicDataSubscriptionBuiltinTopicData 中间接执行此操作。这是 DDS 规范所允许的。

    在标题为 Detect the presence of DomainParticipants, DataWriters and DataReaders in the DDS Domain 的 HOWTO 中有关于如何使用内置主题的信息。 HOWTO 包含一些工作示例代码。它使用 Java 而不是 C#,但应该很容易映射。此处的示例一次读取一个 Sample,因此您无需处理序列语法。

    必须使用的理由:

    DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();
    

    代替:

    DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
    

    读取/获取 API 是否具有两种不同的行为,具体取决于传递的序列是“空”(即分配的/最大长度为零)还是分配的长度。

    如果序列是空的,这是你使用默认构造函数得到的,那么 read/take 表现为零拷贝 API。这意味着序列中的实际元素是从已经存储在中间件中的元素“借来的”。出于这个原因,必须传入的序列必须是“空”序列,以便中间件知道可以将内容替换为对内部元素的引用。访问元素后,您必须将“借出的元素”返回给调用DataReader::return_loan 操作的中间件。

    如果序列不为空。然后 DDS 将假定元素是预先分配的,并会尝试将数据复制到您传递的元素中。您显示的代码的问题是

    DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
    

    仅分配序列本身。但不是元素。因此,当它尝试制作副本时,read/take 调用将失败。如果您想使用这个非零拷贝 API,您必须在调用之后分配每个元素的分配/分配,即:

    for (int i=0; i< 10; i++ ) {
        infoSeq.set_at(i, new DDS.SampleInfo());
    }
    

    同样的情况也适用于数据序列。 如果您这样做,您将不必使用DataReader::return_loan 操作。但是会有额外的副本,所以效率较低。

    您可以在标题为 Howto use OMG DDS Sequences in C++ 的 HOWTO 中找到有关如何使用 DDS 序列的更多信息。它是用 C++ 示例编写的,但原则适用于所有语言。

    问候, 杰拉尔多

    【讨论】:

    • 感谢您的澄清!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 2018-06-17
    • 2016-06-10
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多