ros2 / ros2cli

ROS 2 command line interface tools
Apache License 2.0
181 stars 162 forks source link

Ros2 node info does not show info for nodes of the same name #279

Open rotu opened 5 years ago

rotu commented 5 years ago

It is possible to launch multiple nodes of the same name. When this happens, those multiple nodes show up in ros2 node list but it is impossible to get info on these nodes with ros2 node info.

In the below example, I have launched a single amcl process which spins up 3 nodes. But since the three nodes were assigned the same name, I can't introspect to see what topics those nodes are listening/publishing on.

$ ros2 node list
/KeystrokeListen
/launch_ros
/launch_ros
/launch_ros
/rover_serial
/ArrowsToTwist
/se_node
/bno055_driver
/rviz
/robot_state_publisher
/joint_state_publisher
/amcl
/rplidar_node
/amcl
/rover
/se_node/transform_listener_impl/transform_listener_impl
/amcl

$ ros2 node info /amcl
/amcl
  Subscribers:
    /parameter_events: rcl_interfaces/msg/ParameterEvent
  Publishers:
    /amcl/transition_event: lifecycle_msgs/msg/TransitionEvent
    /parameter_events: rcl_interfaces/msg/ParameterEvent
    /rosout: rcl_interfaces/msg/Log
  Services:
    /amcl/change_state: lifecycle_msgs/srv/ChangeState
    /amcl/describe_parameters: rcl_interfaces/srv/DescribeParameters
    /amcl/get_available_states: lifecycle_msgs/srv/GetAvailableStates
    /amcl/get_available_transitions: lifecycle_msgs/srv/GetAvailableTransitions
    /amcl/get_parameter_types: rcl_interfaces/srv/GetParameterTypes
    /amcl/get_parameters: rcl_interfaces/srv/GetParameters
    /amcl/get_state: lifecycle_msgs/srv/GetState
    /amcl/get_transition_graph: lifecycle_msgs/srv/GetAvailableTransitions
    /amcl/list_parameters: rcl_interfaces/srv/ListParameters
    /amcl/set_parameters: rcl_interfaces/srv/SetParameters
    /amcl/set_parameters_atomically: rcl_interfaces/srv/SetParametersAtomically
ivanpauno commented 5 years ago

I think that the idea is to enforce node name uniqueness, but it has not been applied yet (see here). The only ticket I see tracking that is https://github.com/ros2/design/issues/187.

rotu commented 5 years ago

I think that the idea is to enforce node name uniqueness

I think that that's a great idea down the road, and it would obviate this issue. But it's also way too easy to have nodes not be unique right now and it's extremely confusing when the tools make this harder to introspect. My naive expectation is that the cli tools should throw up a warning and print info on all the nodes with that same name.

Is that duplicate node in ros2 node list a caching issue in the daemon (and therefore not actually a live node at all)? Is it two instances of the same node accidentally being spun up in a launch file? Is it a TransformListener node being launched deep in some library my code is using? Is it someone else on the same network using ROS?

ivanpauno commented 5 years ago

My naive expectation is that the cli tools should throw up a warning and print info on all the nodes with that same name.

The problem is that that change would require changes in the cli, rclpy, rcl, rmw, and in each rmw implementation. For example, for getting the subscribers info, the cli creates a node (with rclpy). Through that node, it ends up calling rcl_get_subscriber_names_and_types_by_node https://github.com/ros2/rcl/blob/ec8539b65c4c2b46d71c3bd6a5a9e25d8ab316b4/rcl/include/rcl/graph.h#L91-L136 That function wraps a similar rmw function. For each rmw implementation that function returns the subscribers info of the first node with that name found.

rotu commented 5 years ago

Ouch! So RCL doesn’t even have a globally unique identifier for nodes?

jacobperron commented 5 years ago

Ouch! So RCL doesn’t even have a globally unique identifier for nodes?

No. I think originally it was assumed that the node names were unique, but this isn't enforced (possibly an oversight?). IMO we should first decide if node names should be unique (ros2/design#187), if not, then we should implement GUIDs for nodes and use it throughout the stack.

nikhilkkr12 commented 5 months ago

include <alsa/asoundlib.h>

include

include

include

include "rcl/rcl.h"

include "std_msgs/msg/byte_multi_array.h"

include "rosidl_runtime_c/primitives_sequence_functions.h" // Include this header for sequence functions

define PCM_DEVICE "default"

define AUDIO_BUFFER_SIZE 4096

// Function declarations int initialize_ros2(int argc, char argv[], rcl_context_t context, rcl_node_t node, rcl_publisher_t publisher); int capture_and_publish_audio(rcl_context_t context, rcl_publisher_t publisher); void cleanup_ros2(rcl_context_t context, rcl_node_t node, rcl_publisher_t *publisher);

int main(int argc, char *argv[]) { rcl_context_t context; rcl_node_t node; rcl_publisher_t publisher;

if (initialize_ros2(argc, argv, &context, &node, &publisher) != 0) {
    return 1;
}

if (capture_and_publish_audio(&context, &publisher) != 0) {
    cleanup_ros2(&context, &node, &publisher);
    return 1;
}

cleanup_ros2(&context, &node, &publisher);
return 0;

}

int initialize_ros2(int argc, char argv[], rcl_context_t context, rcl_node_t node, rcl_publisher_t publisher) { rcl_ret_t ret;

// Initialize ROS 2 options
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_allocator_t allocator = rcl_get_default_allocator();
ret = rcl_init_options_init(&init_options, allocator);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error initializing ROS 2 options\n");
    return 1;
}

// Initialize ROS 2 context
*context = rcl_get_zero_initialized_context();
ret = rcl_init(argc, (const char * const *)argv, &init_options, context);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error initializing ROS 2 context\n");
    return 1;
}

// Create a ROS 2 node
*node = rcl_get_zero_initialized_node();
const char * node_name = "audio_publisher";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(node, node_name, "", context, &node_options);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error initializing ROS 2 node\n");
    return 1;
}

// Create a ROS 2 publisher
*publisher = rcl_get_zero_initialized_publisher();
const rosidl_message_type_support_t * msg_type_support = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, ByteMultiArray);
const char * topic_name = "audio_data";
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
ret = rcl_publisher_init(publisher, node, msg_type_support, topic_name, &publisher_options);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error initializing ROS 2 publisher\n");
    return 1;
}

return 0;

}

int capture_and_publish_audio(rcl_context_t context, rcl_publisher_t publisher) { // Open the PCM device for recording snd_pcm_t *handle; if (snd_pcm_open(&handle, PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0) < 0) { fprintf(stderr, "Error opening PCM device %s\n", PCM_DEVICE); return 1; }

// Set parameters for recording
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
unsigned int sample_rate = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &sample_rate, 0);
if (snd_pcm_hw_params(handle, params) < 0) {
    fprintf(stderr, "Error setting PCM parameters\n");
    snd_pcm_close(handle);
    return 1;
}

// Buffer for captured audio
uint8_t buffer[AUDIO_BUFFER_SIZE];

// Create ROS 2 message
std_msgs__msg__ByteMultiArray msg;
std_msgs__msg__ByteMultiArray__init(&msg);
if (!rosidl_runtime_c__uint8__Sequence__init((rosidl_runtime_c__uint8__Sequence *)&msg.data, AUDIO_BUFFER_SIZE)) {
    fprintf(stderr, "Error initializing ByteMultiArray sequence\n");
    return 1;
}

// Publish captured audio
while (rcl_context_is_valid(context))
{
    // Read audio data
    int frames = snd_pcm_readi(handle, buffer, AUDIO_BUFFER_SIZE / 4); // 2 bytes per sample, 2 channels
    if (frames < 0) {
        frames = snd_pcm_recover(handle, frames, 0);
    }
    if (frames < 0) {
        fprintf(stderr, "Error reading audio data: %s\n", snd_strerror(frames));
        break;
    }

    // Assign buffer data to ROS 2 message
    memcpy(msg.data.data, buffer, frames * 4); // 4 bytes per frame (2 bytes per sample, 2 channels)
    msg.data.size = frames * 4;

    // Publish audio data
    rcl_ret_t ret = rcl_publish(publisher, &msg, NULL);
    if (ret != RCL_RET_OK)
    {
        fprintf(stderr, "Error publishing audio\n");
    }

    // Sleep for a short duration
    usleep(10000); // 10 ms
}

// Clean up ROS 2 message
std_msgs__msg__ByteMultiArray__fini(&msg);

// Close PCM device
snd_pcm_close(handle);

return 0;

}

void cleanup_ros2(rcl_context_t context, rcl_node_t node, rcl_publisher_t *publisher) { rcl_ret_t ret;

// Shutdown ROS 2 resources
ret = rcl_publisher_fini(publisher, node);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error finalizing ROS 2 publisher\n");
}

ret = rcl_node_fini(node);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error finalizing ROS 2 node\n");
}

ret = rcl_shutdown(context);
if (ret != RCL_RET_OK)
{
    fprintf(stderr, "Error shutting down ROS 2 context\n");
}

} this is my publisher code, i am trying to capture the audio and send it to the P.C means from SOM to PC, SOM(nvidia jetson agx developer kit 64 gb). The environment is ROS2 environment. Can you please help me out.

clalancette commented 5 months ago

That question has nothing to do with this issue. Please open a question over on https://robotics.stackexchange.com/questions/tagged/ros, which is our central Question and Answer site. You'll get a better answer there, and it will be searchable for the future.

Make sure to include a lot of information on what platform you are using, which ROS distribution you are using, and the exact steps you took.