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

Handling namespace for multiple CameraInfoManagers in ROS2 jazzy #341

Open
PfeifferMicha opened this issue Feb 4, 2025 · 4 comments
Open

Comments

@PfeifferMicha
Copy link

Hi,

I'm trying to set up the driver for a stereo camera, so I need two CameraInfoManager instances.
The hope was that I could set up the classes in such a way that they advertise:

/stereo/node_name/left/set_camera_info and 
/stereo/node_name/right/set_camera_info

However, they always seem to end up advertising the exact same service name...?

/stereo/node_name/set_camera_info

Is there a workaround?

I saw that on the rolling branch, there is a "namespace" (ns) parameter that one can pass to the CameraInfoManager constructor, however it's missing on the jazzy branch. Is there a workaround? Or could this be backported?

@sloretz
Copy link
Contributor

sloretz commented Feb 4, 2025

The feature you're looking for was added in #324, and it was not backported because it breaks ABI. It does mention

Up until Jazzy this could have been remedied by using a sub-node with its custom namespace, however since updating the code to work with lifecycle nodes this is not possible anymore.

If you're using normal nodes, you could create a sub-node and pass it to this constructor

CameraInfoManager::CameraInfoManager(
rclcpp::Node * node, const std::string & cname,
const std::string & url)
: CameraInfoManager(node->get_node_base_interface(),
node->get_node_services_interface(), node->get_node_logging_interface(), cname, url)
{
}

@PfeifferMicha
Copy link
Author

Thank you, I think sub-nodes is what I was looking for, I wasn't aware that they exist!

However, I've had no luck so far. Here's my code:

    auto nh = rclcpp::Node::make_shared( "split_image" );

    auto nhLeftFullscale = nh->create_sub_node("left_fullscale");
    auto nhRightFullscale = nh->create_sub_node( "right_fullscale");

    RCLCPP_INFO_STREAM( rclcpp::get_logger("rclcpp"),
                        "Sub-node initialized in: " << nhLeftFullscale->get_effective_namespace() );
    RCLCPP_INFO_STREAM( rclcpp::get_logger("rclcpp"),
                        "Sub-node initialized in: " << nhRightFullscale->get_effective_namespace() );

    image_transport::ImageTransport itLeftFullscale( nhLeftFullscale );
    image_transport::ImageTransport itRightFullscale( nhRightFullscale );

    m_pubLeftFullscale = itLeftFullscale.advertiseCamera("left_fullscale/image_raw", 10);
    m_pubRightFullscale = itRightFullscale.advertiseCamera("right_fullscale/image_raw", 10);

    m_camInfoManagerLeftFullscale = std::make_shared<camera_info_manager::CameraInfoManager>(
         nhLeftFullscale.get(), "left" );
    m_camInfoManagerRightFullscale = std::make_shared<camera_info_manager::CameraInfoManager>(
         nhRightFullscale.get(), "right" );

This correctly outputs:

[component_container-2] [INFO] [1738751665.628093063] [rclcpp]: Sub-node initialized in: /stereo/left_fullscale
[component_container-2] [INFO] [1738751665.628116356] [rclcpp]: Sub-node initialized in: /stereo/right_fullscale

... and the image transport topics are correctly published under /stereo/[left|right]_fullscale/[image_raw|camera_info].

However, it only creates this service (and calling it hangs indefinitely)
/stereo/split_node_container/set_camera_info
I was expecting to have these services, which don't exist:

/stereo/left_fullscale/set_camera_info
/stereo/right_fullscale/set_camera_info

Is this related to the fact that I'm running all of this in a component? Does the component container somehow "swallow" the services?

@sloretz
Copy link
Contributor

sloretz commented Feb 5, 2025

I was expecting to have these services, which don't exist:

/stereo/left_fullscale/set_camera_info
/stereo/right_fullscale/set_camera_info

I would expect the same given that the service uses the name ~/set_camera_info in Jazzy. This seems like a bug to me, but I'm not sure where yet. Maybe it's because rclcpp::create_service takes a NodeBaseInterface, and that doesn't include sub-node info? (@wjwwood does that sound like a possible cause?)

Is this related to the fact that I'm running all of this in a component? Does the component container somehow "swallow" the services?

I would not expect the component container to affect this. Components share the context object, but IIRC remapping names happens on Nodes, and components don't share Nodes. I'm very surprised by the name /stereo/split_node_container/set_camera_info.

I think next step to resolving this is to come up with a minimal reproducible example, maybe using just the rclcpp APIs used CameraInfoManager. @PfeifferMicha Is that something you'd be willing to take on?

@PfeifferMicha
Copy link
Author

PfeifferMicha commented Feb 6, 2025

Sure, here's a minimal example using two sub-nodes and two CameraInfoManagers. I used jazzy to run this, but it'd be interesting to see if other distros are affected as well.

While the node is running, I see one set_camera_info service in the main node's namespace, even though clearly two are created (and they use two different sub-nodes):

/test_cam_info_manager/describe_parameters
/test_cam_info_manager/get_parameter_types
/test_cam_info_manager/get_parameters
/test_cam_info_manager/get_type_description
/test_cam_info_manager/list_parameters
/test_cam_info_manager/**set_camera_info**
/test_cam_info_manager/set_parameters
/test_cam_info_manager/set_parameters_atomically

I've also been searching for other repositories who use CameraInfoManager with stereo cameras, but I've not had any luck of finding a good, simple, working example. I thought this was the standard way of doing things?

Edit:
As a test, I tried adding this to the CameraInfoManager's constructor:

std::string resolved_service_name = node_base_interface->resolve_topic_or_service_name( 
                                                               "~/set_camera_info", true, false );

This resolves to: /test_cam_info_manager/set_camera_info, but in my opinion it should resolve to /test_cam_info_manager/left/set_camera_info. It looks like the sub-node's namespace is being ignored entirely. As far as I understand, this is not image_common's code, so I'll open an issue upstream. Reference: ros2/rclcpp#2734

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

No branches or pull requests

2 participants