0
$\begingroup$

Rosanswers logo

I am interfacing a ROS2 subscriber with a native RTI DDS publisher.

I have the following message structure for the message named DetectedObjectList

int16 id

//an array of objects of another message type

DetectedObject[ ] objects

and the DetectedObject.msg is defined as follows :

int16 id
 
int16 x

int16 y

I am publishing an id and an object of type DetectedObject

To Simplify the problem, now my msg file contains only int16 id.

If I look at the RTI Admin Console, the datatypes in the ROS2 listener and RTI are matched and everything seems to be ok.

I feel I am doing something wrong in the ROS2 listener node. Here is the snippet for my ROS2 listener

EDIT : Full ROS2 code.

import sys
import rclpy
from rclpy.node import Node

from openadx_msg.msg import (DetectedObjectList, DetectedObject)

class DemoNode(Node):

    def __init__(self):
        super().__init__('ros2_listener')
        self.sub = self.create_subscription(DetectedObjectList, 'vehicle/objects', self.object_callback)
    
    def object_callback(self,msg):
        print("entering callback")
        log = self.get_logger().info
        log('Received a message')
        log('id: {}.format(msg.id)')

def main(args=None):
    if args is None:
        args=sys.argv
    node=DemoNode()    // EDIT2
    rclpy.spin(node)

    node.destroy_node()
    rclpy.shutdown()

if __name__=='__main__':  //EDIT3
    main()

Here is the code for the RTI DDS python connector :

from __future__ import print_function
from ctypes import *
import sys
import os
from sys import path as sysPath
from os import path as osPath
from time import sleep
import math
filepath = osPath.dirname(osPath.realpath(__file__))
sysPath.append(filepath + "/../../../")
import rticonnextdds_connector as rti

def main():


    connector = rti.Connector("MyParticipantLibrary::Zero",
                          filepath + "/../ROS2_demo_nodes_py.xml")
    outputDDS = connector.getOutput("MyPublisher::VehicleObjectWriter")


    for i in range(1,50000):
            
            
            outputDDS.instance.setNumber("id_",i)
            outputDDS.write()

            toPrint = "id_ : " + repr(i)
            print(toPrint)
            

                    


if __name__== "__main__":
    main()

And here is the xml file used by this connector. The xml is a translated version of the ROS2 IDL file.

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://community.rti.com/schema/5.1.0/rti_dds_profiles.xsd" version="5.1.0">

    <!-- Qos Library -->
    <qos_library name="QosLibrary">
        <qos_profile name="DefaultProfile" is_default_qos="true" base_name="BuiltinQosLib::Generic.510TransportCompatibility">
            <datawriter_qos>
                <property>
                    <value>
                        <element>
                        <name>dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size</name>
                        <value>2147483647</value>
                        </element>
                    </value>
                </property>
            </datawriter_qos>
            
            <datareader_qos>
                <property>
                    <value>
                        <element>
                        <name>dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size</name>
                        <value>2147483647</value>
                        </element>
                    </value>
                </property>
            </datareader_qos>
            <publisher_qos>
                <partition>
                    <name>
                        <element>rt/vehicle</element>
                    </name>
                </partition>
            </publisher_qos>
            <subscriber_qos>
                <partition>
                    <name>
                        <element>rt/vehicle</element>
                    </name>
                </partition>
            </subscriber_qos>
            <participant_qos>
                <transport_builtin>
                    <mask>UDPV4 | SHMEM</mask>
                </transport_builtin>
            </participant_qos>
        </qos_profile>
    </qos_library>

    <!-- types -->
    <types>
    <module name="openadx_msgs">
    <module name="msg">
    <module name="dds_">
      <const name="VehicleControl__GEAR_KEEP" type="int32" value="-1"/>
      <const name="VehicleControl__GEAR_PARK" type="int32" value="0"/>
      <const name="VehicleControl__GEAR_NEUTRAL" type="int32" value="1"/>
      <const name="VehicleControl__GEAR_DRIVE" type="int32" value="2"/>
      <const name="VehicleControl__GEAR_REVERSE" type="int32" value="3"/>
      <struct name= "VehicleControl_">
        <member name="accelerator_pedal_" type="float64"/>
        <member name="brake_pedal_" type="float64"/>
        <member name="steering_wheel_" type="float64"/>
        <member name="gear_" type="int32"/>
      </struct>
    </module>
    </module>
    </module>
    
    <module name="openadx_msgs">
    <module name="msg">
    <module name="dds_">
     <struct name= "DetectedObject_">
        <member name="id_" type="int32"/>
        <member name="x_" type="float32"/>
        <member name="y_" type="float32"/>
        <member name="v_rad_" type="float32"/>
        <member name="a_rad_" type="float32"/>
      </struct>
    </module>
    </module>
    </module>
    
       
    <module name="openadx_msgs">
    <module name="msg">
    <module name="dds_">
      <struct name= "DetectedObjectList_">
        <!--member name="header_" type="nonBasic"  nonBasicTypeName= "std_msgs::msg::dds_::Header_"/-->
        <member name="id_" type="int16"/>
        <!--member name="objects_" sequenceMaxLength="2147483647" type="nonBasic"  nonBasicTypeName= "openadx_msgs::msg::dds_::DetectedObject_" /-->
      </struct>
    </module>
    </module>
    </module>
    </types>



    <!-- Domain Library -->
    <domain_library name="MyDomainLibrary">
        <domain name="MyDomain" domain_id="0">
            <register_type name="openadx_msgs::msg::dds_::VehicleControl_"  type_ref="openadx_msgs::msg::dds_::VehicleControl_" />
            <topic name="control"    register_type_ref="openadx_msgs::msg::dds_::VehicleControl_"/>
            <register_type name="openadx_msgs::msg::dds_::DetectedObjectList_"  type_ref="openadx_msgs::msg::dds_::DetectedObjectList_" />
            <topic name="objects"    register_type_ref="openadx_msgs::msg::dds_::DetectedObjectList_"/>
        </domain>
    </domain_library>


    <!-- Participant library -->
    <domain_participant_library name="MyParticipantLibrary">
      <domain_participant name="Zero" domain_ref="MyDomainLibrary::MyDomain">

        <publisher name="MyPublisher">
          <data_writer name="VehicleObjectWriter" topic_ref="objects" />
        </publisher>
      
        <subscriber name="MySubscriber">
          <data_reader name="VehicleControlReader" topic_ref="control" />
        </subscriber>

        </domain_participant>
   </domain_participant_library>
</dds>

But my ROS2 node is not entering the callback function. Any idea what am I doing wrong ?


Originally posted by aks on ROS Answers with karma: 667 on 2018-08-06

Post score: 1


Original comments

Comment by sloretz on 2018-08-06:
Would you mind posting a full source file showing the issue? I suspect rclpy.spin() isn't being called, but I can't say for sure without seeing more of the code.

Comment by aks on 2018-08-06:
@sloretz : I have updated the code

Comment by Dirk Thomas on 2018-08-06:
Have you tried publishing a dummy message using the command line tool ros2 topic pub ...? That should at least show you if the problem is in your subscriber or on the publisher side.

Comment by aks on 2018-08-06:
Yes, I have tried that. Publishing from ROS2, I can subscribe on the native DDS Application. I have also broken down the problem , publishing a simple string on the topic chatter and run the listener.py node in ROS2 but it still doesnt subscribe. Debugging it->doesnt enter callback. dont know y

Comment by Dirk Thomas on 2018-08-06:
If none of the tutorials work for you you might want to check if your network interface support multicasts.

Comment by aks on 2018-08-07:
The machine on which I run native DDS does not support multicast but i guess this should not be a problem as the communication is working in one direction.

$\endgroup$

2 Answers 2

1
$\begingroup$

Rosanswers logo

I found the problem.

RTI interprets unbounded string as MAX_SIZE_INT32 which is 2147483647. I had a variable in header as string frame_id. To establish communication between ROS2 and native DDS, the types should be same. So, in the QoS.xml, I gave the maxStringLength = 2147483647. This gave an error create DataWriter buffer pool. Refering to the RTI community, I created an extra QoS setting for the data_writer and data_reader :

    <datawriter_qos>
        <property>
            <value>
                <element>
                <name>dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size</name>
                <value>2147483647</value>
                </element>
            </value>
        </property>
    </datawriter_qos>
    <datareader_qos>
        <property>
            <value>
                <element>
                <name>dds.data_writer.history.memory_manager.fast_pool.pool_buffer_max_size</name>
                <value>2147483647</value>
                </element>
            </value>
        </property>
    </datareader_qos>

This somehow lead to improper memory management and ROS2 wasnt able to subscribe any messages (not enterin the callback). I reduced the buffer size of the datawriter to 2046 and now it works perfectly fine.

Question : Although I have found out the error, I am still not sure what are the possible reasons for it. Is it only memory creation problem ?


Originally posted by aks with karma: 667 on 2018-08-07

This answer was NOT ACCEPTED on the original site

Post score: 2

$\endgroup$
0
$\begingroup$

Rosanswers logo

The problem is you're not creating an instance of your DemoNode object at any point. If you look at this subscriber example you can see the structure you need.

Your main should look something like this:

def main(args=None):
    if args is None:
        args=sys.argv

    demo_node = DemoNode()
    rclpy.spin(demo_node)

    demo_node.destroy_node()
    rclpy.shutdown()

Hope this helps.


Originally posted by PeteBlackerThe3rd with karma: 9529 on 2018-08-06

This answer was NOT ACCEPTED on the original site

Post score: 1


Original comments

Comment by aks on 2018-08-06:
@PeterBlackerThe3rd...Thanks for noticing that. I already had that in my code but while typing the code manually in this post, I missed it by mistake. Sorry for the confusion.

Comment by PeteBlackerThe3rd on 2018-08-06:
It might be another copy n paste error but you're second to last line should be

if __name__ == '__main__':

Comment by PeteBlackerThe3rd on 2018-08-06:
You could put a couple of print statements in main and DemoNode.__init__ to check they're being setup properly.

Comment by Dirk Thomas on 2018-08-06:
The easiest would be to share the complete code of a package as well as the exact line of a publisher cli invocation. Than readers can try your case in literally a minute and comment if it is a problem in your code or not.

Comment by aks on 2018-08-07:
Updated the entire code

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.