Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question [ROS-TCP-Connector] Publishing performance drop when subscriber and publisher are active

Discussion in 'Robotics' started by lazyrobotboy, Jan 19, 2022.

  1. lazyrobotboy

    lazyrobotboy

    Joined:
    Jul 1, 2020
    Posts:
    16
    Hey everyone,

    noticed a strange behaviour while communicating with ROS topics from within Unity using the ROS-TCP-Connector:
    - I do publish joint angles to a robot with a position publisher
    - As soon as I also activate a subscriber, the position publishing is not working smoothly, the robot movements become "stuttering"

    Minimal example of the position publisher:
    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Robotics.ROSTCPConnector;
    3. using PositionUnity = RosMessageTypes.Std.Float64MultiArrayMsg;
    4. using System.Collections;
    5.  
    6. public class PositionPublisher : MonoBehaviour
    7. {
    8.     [SerializeField] private string _rosTopic = "PositionController/command";
    9.     [SerializeField] private ROSConnection _ROS;
    10.     [SerializeField] private float _publishMessageFrequency = 0.01f;
    11.     private float timeElapsed;
    12.     private PositionUnity _message;
    13.  
    14.     void Start()
    15.     {
    16.         _ROS = ROSConnection.GetOrCreateInstance();
    17.         _ROS.RegisterPublisher<PositionUnity>(_rosTopic);
    18.         InitializeMessage();
    19.     }
    20.  
    21.     private void InitializeMessage()
    22.         {
    23.             _message = new RosMessageTypes.Std.Float64MultiArrayMsg
    24.             {
    25.                 data = new double[7],
    26.                 layout = new RosMessageTypes.Std.MultiArrayLayoutMsg
    27.                 {
    28.                     data_offset = 0,
    29.                     dim = new RosMessageTypes.Std.MultiArrayDimensionMsg[]
    30.                     {
    31.                         new RosMessageTypes.Std.MultiArrayDimensionMsg {
    32.                             label = "",
    33.                             size = 7,
    34.                             stride = 1
    35.                         }
    36.                     }
    37.                 }
    38.             };
    39.         }
    40.  
    41.     private void Update()
    42.     {
    43.         timeElapsed += Time.deltaTime;
    44.         if (timeElapsed >_publishMessageFrequency)
    45.         {
    46.             _message.data[0] = jointPosition1; // just an example
    47.             // continue for more joints
    48.  
    49.             _ROS.Publish(_rosTopic, _message);
    50.             timeElapsed = 0;
    51.         }
    52.     }
    53. }
    Minimal example of a subscriber:
    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Robotics.ROSTCPConnector;
    3. using SensorUnity = RosMessageTypes.Std.Float32MultiArrayMsg;
    4. using System.Collections;
    5.  
    6. public class ExternalTorqueSubscriber : MonoBehaviour
    7. {
    8.     [HideInInspector] public float externalTorqueJ1;
    9.     [SerializeField] private string rosTopic = "external_torques";
    10.     [SerializeField] private ROSConnection _ROS;
    11.  
    12.     void Start()
    13.     {
    14.         _ROS = ROSConnection.GetOrCreateInstance();
    15.         _ROS.Subscribe<SensorUnity>(rosTopic, GetExternalTorques);
    16.     }
    17.     private void GetExternalTorques(SensorUnity sensorMsg)
    18.     {
    19.         // StartCoroutine(GetExternalTorqueValues(sensorMsg));
    20.     }
    21.  
    22.     IEnumerator GetExternalTorqueValues(SensorUnity message)
    23.     {
    24.         // externalTorqueJ1 = message.data[0]; // example
    25.         // yield return null;
    26.     }
    27.     public void UnSub()
    28.     {
    29.         _ROS.Unsubscribe(rosTopic);
    30.     }
    31. }
    Also interesting: The subscriber does not necessarily have to process any data, simply subscribing leads to the uneven robot motion. This is why the coroutine and commented out.
    And we are talking about some floats/ints being sent, nothing big in traffic, this is what baffles me.

    Am I missing something important regarding the subscribing/publishing of the ROS-TCP-Connector?


    TL;DR:
    Sending positions to the robot with a publisher in Unity results in fluid motion.
    As soon as even one subscriber is opened in Unity, the robot's movement becomes stuttery.
    Why?
     
  2. LaurieUnity

    LaurieUnity

    Unity Technologies

    Joined:
    Oct 23, 2020
    Posts:
    77
    Hmm. It's not obvious why this would happen. Calling Subscribe does of course result in extra network traffic, since now you're subscribed to the external_torques topic and Unity is receiving all those messages. And there will be some extra processing due to deserializing the messages and calling your callback, but I can't imagine that would be expensive enough to cause a visible stutter.
    Roughly how many messages are being sent on this topic?
     
  3. lazyrobotboy

    lazyrobotboy

    Joined:
    Jul 1, 2020
    Posts:
    16
    Hi Laurie,

    7 floats (one value for every robot joint) and I have dropped the publishing rate on the ROS-side to 5 Hz, this did not lead to any visible improvement. I have seen examples of people sending 28 full HD images with 1 Hz, my assumption would be that my traffic is nothing in comparison to that.
    Could the "Float32MultiArrayMsg" itself be the problem and I should use a different message type or do you have any other suggestion where to look/improve?
     
  4. LaurieUnity

    LaurieUnity

    Unity Technologies

    Joined:
    Oct 23, 2020
    Posts:
    77
    Ok, yeah, for that amount of traffic there's no way it can be a problem with bandwidth or processing time. Mysterious - I'm not sure what it can be. Maybe try to strip away all the irrelevant stuff from your project to make a minimal repro case, and see if you still get the problem - and if you do, share the project with us?
     
  5. lazyrobotboy

    lazyrobotboy

    Joined:
    Jul 1, 2020
    Posts:
    16
    Hey Laurie, is there any convenient way to debug or check the traffic? Maybe even from within Unity? I don't know if publishing and subscribing some floats with 200 Hz is already a bottleneck for the ROS-TCP-Connector.

    Also, is it necessary for Unity to at least have the subscribing/publishing frequency as FPS? Or could you still subscribe to a topic with 200 Hz even if your Unity project runs at e.g. 60 Hz? Thanks in advance.
     
  6. LaurieUnity

    LaurieUnity

    Unity Technologies

    Joined:
    Oct 23, 2020
    Posts:
    77
    For performance issues in general, we suggest you try the new beta version of Ros-Tcp-Endpoint, rewritten in C++. (https://github.com/Unity-Technologies/ROS-TCP-Endpoint/tree/Roscpp).
    It should Just Work if you're using the launch file; if you rosrun the executable yourself, the command is now `rosrun ros-tcp-endpoint endpoint`. Let us know how that works out.

    As for publishing frequency: You certainly can subscribe to a 200Hz topic, and it should work fine - except that incoming messages are stored in a queue until subscriber callbacks get called on Update (i.e. once per frame). So your callbacks won't be evenly distributed, they'll probably execute in batches of 3 or 4.
     
  7. rhee1998

    rhee1998

    Joined:
    Sep 3, 2020
    Posts:
    1
    I encountered similar problem where I published and subscribed a ROS message containing a couple of floats. At first, I thought that there was some issues with the TCP/IP networking, but later found out that the source code for ROS node was faulty. Can you post the scripts on the ROS side?
     
  8. lazyrobotboy

    lazyrobotboy

    Joined:
    Jul 1, 2020
    Posts:
    16
    I have tested the cpp-version, it's working but I still have communication issues. Right now I am trying to publish positions with 100 Hz to two different robots, which works fine. Subscribing simultaneously (message with 6 ints) is a huge problem and just doesn't work. It works with 3 Hz but as soon as I try to up that to for instance 50 Hz I encounter the error "Reader 102 exception! System.OverflowException" within Unity on startup. I have tried different versions of ROS-TCP, different rates, different message types ... Is Unity probably just not suited to subscribe to two systems with 50+ Hz (6 ints) while publishing to these two systems with 100 Hz (7 floats)? What's the bottle neck in this case?

    Maybe that is the problem, I don't know. Here is a minimal example of the topic I am publishing on the ROS-side:
    Code (Python):
    1. import rospy
    2. import time
    3. import numpy as np
    4. import std_msgs.msg import Int32MultiArray
    5.  
    6. class ExamplePublisher():
    7.     def __init__(self):
    8.         self.init_node('example_node', anonymous=False)
    9.         self.rate = rospy.Rate(50)
    10.         rospy.Subscriber("/example_subscriber", ...)
    11.         rospy.pub_example = rospy.Publisher('/example', Int32MultiArray, queue_size=1)
    12.  
    13.     def example_calculation(self):
    14.         while not rospy.is_shutdown():
    15.             try:
    16.                 self.example_calculation = ... # some numpy stuff
    17.  
    18.             except rospy.ServiceException as e:
    19.                 print("Service did not process request: " + str(e))
    20.  
    21.             self.example_i32 = Int32MultiArray()
    22.             self.example_i32.data = self.example_calculation
    23.             self.pub_example.publish(self.example_i32)
    24.             self.rate.sleep()
    25.  
    26. if __name__ == '__main__':
    27.     try:
    28.         example_c = ExamplePublisher()
    29.         example_c.example_calculation()
    30.     except rospy.ROSInterruptException:
    31.         pass
    Right now I am also using "connect on start" on both ROS_Connections in Unity. Maybe the system is just overwhelmed by the amount of message to process during startup of the Unity application? Any other ideas where I can improve my setup?


    Interesting side note:
    When connecting to just one robot I can publish and subscribe with a rate of 100 Hz without problems but when I add the second robot, I have to reduce the subscriber to 3 Hz in order to bypass a disconnect. It seems like the second subscriber puts a big load of stress onto the system. Meanwhile the task manager shows a mere network load of 40/80 KBit/s for sending/receiving. Very strange ...
     
    Last edited: Sep 6, 2022