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

Fix: /tf and /static_tf topics' inconsistencies #2676

Merged

Conversation

Arun-Prasad-V
Copy link
Contributor

@Arun-Prasad-V Arun-Prasad-V commented Mar 31, 2023

Fixing #2522

Issues Fixed:

  1. /static_tf topic is getting listed even when publish_tf:=false
  2. When the tf_publish_rate param is dynamically changed from 0.0 to >0.0, /tf topic is not getting published
  3. /tf topic has only the TFs of last started sensor and not the TFs of previously started sensors

@Arun-Prasad-V Arun-Prasad-V marked this pull request as ready for review March 31, 2023 04:11
@Arun-Prasad-V Arun-Prasad-V marked this pull request as draft March 31, 2023 05:55
Copy link
Collaborator

@SamerKhshiboun SamerKhshiboun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch @Arun-Prasad-V ! Working good also on my environment.
As we fix this, I think we can add a warning also when disabling the dynamic tf
so, as we have in line 989:
ROS_WARN("Publishing dynamic camera transforms (/tf) at %g Hz", _tf_publish_rate);
We can add something similar at line ~1002, something like:
ROS_WARN("Publishing dynamic camera transforms to topic (/tf) has been stopped");

so, when user do
ros2 param set /camera/camera tf_publish_rate 0.0
he will get warning about that

@@ -37,7 +37,6 @@ void BaseRealSenseNode::getParameters()
startDynamicTf();
});
_parameters_names.push_back(param_name);
startDynamicTf();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change the behavior from default start publishing to not?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the node is started, "startDynamicTf()" is getting called twice. So, the prints are also coming twice as shown below:
image

With this change, it will be called only once.

Basic testing is done. Will test for corner cases as well.

@Arun-Prasad-V Arun-Prasad-V marked this pull request as ready for review April 10, 2023 06:10
@SamerKhshiboun
Copy link
Collaborator

As I tested it now, if we put pulish_tf:=false,
and in another terminal runros2 topic list, we will still see /tf_static as topic (it is an empty one, not publishing anything)
I would prefer to not starting this topic at all.
We can do this by moving _static_tf_broadcaster init to be inside the publishStaticTransform
It will look something like this:

void BaseRealSenseNode::publishStaticTransforms(std::vector<rs2::stream_profile> profiles)
{
    // Publish static transforms
    if (_publish_tf)
    {
        if(!_static_tf_broadcaster)
        {
            // intra-process do not support latched QoS, so we need to disable intra-process for this topic
            rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options;
            options.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;

#ifndef DASHING
            _static_tf_broadcaster = std::make_shared<tf2_ros::StaticTransformBroadcaster>(_node, tf2_ros::StaticBroadcasterQoS(), std::move(options));
#else
            _static_tf_broadcaster = std::make_shared<tf2_ros::StaticTransformBroadcaster>(_node, rclcpp::QoS(100), std::move(options));
#endif
        }
        
        for (auto &profile : profiles)
        {
            calcAndPublishStaticTransform(profile, _base_profile);
        }
.
.
.

This way, we will not see any of /tf_static and /tf topics if publish_tf:=false

@@ -58,6 +58,7 @@
{'name': 'initial_reset', 'default': 'false', 'description': "''"},
{'name': 'allow_no_texture_points', 'default': 'false', 'description': "''"},
{'name': 'pointcloud.ordered_pc', 'default': 'false', 'description': ''},
{'name': 'publish_tf', 'default': 'true', 'description': 'enable/disable publishing tf'},
Copy link
Collaborator

@SamerKhshiboun SamerKhshiboun Apr 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to explain more in the description field, specially for these two parameters since they can confuse users.

  • publish_tf: [bool] enable/disable publishing static or dynamic TF
  • tf_publish_rate: [double] rate in HZ for publishing dynamic TF

Also, I would prefer to explanation and elaborate more in the README.md file, where we explain about publish_rate and tf_publish_rate
1- to explain that publish_tf:=false will not publish any static/dynamic TFs, even if tf_publish_rate is bigger than 0.0
2- to explain that publish_tf:=true, will automatically publish static TFs. If dynamic TFs are needed, user should set the tf_publish_rate for it, and it should be > 0.0
3- to mention that the default value is publish_tf:=true with tf_publish_rate:=0.0 which means publishing static TFs as default behavior.

@SamerKhshiboun
Copy link
Collaborator

SamerKhshiboun commented Apr 12, 2023

Take into mind that this fix is not covering the whole problem from issue #2522
@Tristis116 rightly claims that not all transformations are transferred when publish Dynamic TFs (/tf topic), since we clear the TF messages. Reference: look for _static_tf_msgs.clear();
Every time we restarts a sensor, we clear these messages.
If we put some debug messages, it looks like something like this:

image

The static broadcaster (tf2_ros::StaticTransformBroadcaster), as a Latched Topic, works like it accumulates inside him all the messages. So, clear of messages is not harming it. Every new sensor we turn on during runtime, the broadcaster will add it's TF to the rest of TFs already in his hand.
Turning off Sensors, will not change anything, and will not remove any TF msg from the published info, and this is okay.

But the dynamic broadcaster (tf2_ros::TransformBroadcaster )is not Latched topic, and it works like normal topics. It looks every time on the _static_tf_msgs we have, and tries to broadcast it. So usually, you will see in /tf topic only the last started sensor TFs, and that is a wrong behavior.

We need to figure out how to solve it, maybe to use a HashMap instead of vector of tf_msgs, (see std::vector<geometry_msgs::msg::TransformStamped> _static_tf_msgs;) where the KEY is the wanted profile or something like a string TF_FROM_TO, and then we clear/fill only by this key.

P.S.
I don't know why we publish dynamic TFs at all, since all the camera parts are statically connected.
So, in our Camera modules, dynamic TFs are the same as static TFs, but they are being published in a specific rate, while the static TFs are being published only when needed (usually once..)

@Arun-Prasad-V Arun-Prasad-V marked this pull request as draft April 12, 2023 04:16
@Arun-Prasad-V
Copy link
Contributor Author

Added fix for the issue "/tf topic has only the TFs of last started sensors"

Root cause:

  • The TFs are stored in static_tf_msgs vector
  • This vector is getting cleared everytime a sensor is started - that's why /tf has only TFs of last started sensor

Fix details:

  • Not clearing static_tf_msgs vector everytime
  • When a sensor is started, add its corresponding TF frames to that vector
  • When a sensor is stopped, erase its corresponding TF frames alone in that vector. So that the TFs of other sensors will be alive
    • The corresponding TFs to be erased are searched and identified in the vector using frame_id & child_frame_id

@Arun-Prasad-V Arun-Prasad-V marked this pull request as ready for review April 21, 2023 11:14
@SamerKhshiboun
Copy link
Collaborator

SamerKhshiboun commented Apr 24, 2023

Great job @Arun-Prasad-V.
I think now we cover all flows and it is working good.
I gave you some comments, and I think we can move all base_realsense::<TFs functions> to a new cpp file tfs.cpp to be dedicated to all TF methods (no need for header file. see parameters.cpp for example).
If you do that, remember to add this cpp to the cmake file

@Arun-Prasad-V Arun-Prasad-V changed the title Avoid configuring dynamic_tf_broadcaster within tf_publish_rate's cb Fix: /tf and /static_tf topics' inconsistencies Apr 25, 2023
const std::string& child_frame_id)
{
std::vector<geometry_msgs::msg::TransformStamped>::iterator it;
struct find_tf
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to move this struct outside this method.
and maybe name it with another name since using find_tf with find_if might be confusing while reading the code.

if (_publish_tf)
{
std::lock_guard<std::mutex> lock_guard(_publish_tf_mutex);
publishStaticTransforms();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we publish static transforms only at this point, then I think we should change calcAndPublishStaticTransforms name to be just calculcateStaticTransforms
or even calcualteTransforms since we use it for static and dynamic TFs
This is affecting line 358


if (_publish_tf)
{
std::lock_guard<std::mutex> lock_guard(_publish_tf_mutex);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this part from line 201 to line 217 should be in a separate function.
Like we have PublishStaticTransforms() which uses publish_static_tf inside it, we can have UnpublishStaticTransforms(<params>) which will use unpublish_static_tf inside it.

}
else
{
ROS_WARN("Currently not publishing dynamic camera transforms (/tf)");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question, can you remind me when we will get to here ? In which scenario ?

}

// intra-process do not support latched QoS, so we need to disable intra-process for this topic
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this part from line 1008 to line 1024 into a seperate function
resetStaticTransformBroadcaster(_static_tf_broadcaster)

Copy link
Collaborator

@SamerKhshiboun SamerKhshiboun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Nir-Az Nir-Az merged commit eb1458f into IntelRealSense:ros2-development Apr 27, 2023
@Arun-Prasad-V Arun-Prasad-V deleted the dynamic_tf_broadcast branch August 10, 2023 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants